Typescript Custom 모듈 정의
Summary
- Typescript compiler는 모듈의 타입을 알아내기 위해 특정한 path를 따른다.
- 모듈 import 시 상대경로 / 비상대경로 에 따라 찾아보는 순서가 다르다 다르다.
tsconfig.json
에서 custom 설정이 가능하다. (path
,typeRoot
,type
등등)
react 에 custom type을 적용하고 싶다면?
- 타입 정의
src/types/index.d.ts
export module "react" {
export type my_custom_type = React.FC;
}
- 모듈 이름에 따라 type을 참조할 path 정의
tsconfig.json
{
"compilerOptions": {
"jsx": "react",
"baseUrl": "./",
**"paths": {"react" : ["./src/types"]},**
"outDir": "dist",
"target": "es5",
"module": "esnext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": false,
"traceResolution": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
- 사용
/src/index.tsx
import React from "react";
import "./App.css";
~~c~~onst App: React.my_custom_type = () => {
return (
<div className="App">
<header translate="no" className="App-header">
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
};
export default App;
TL;DR
제가 모르고 있었던 부분을 정리했습니다. 타입스크립트 컴파일러와 컴파일러가 타입을 찾는 과정, index.d.ts 파일 구조, ambient module에 대해 아래에서 설명합니다.
타입스크립트 컴파일러
microsoft/TypeScript-React-Starter
타입스크립트 컴파일러: 타입스크립트 → 자바스크립트 tsc
타입스크립트 컴파일러가 해주는 일은?
type checking 정의한 type을 참고해 정의된 타입과 사용된 타입이 일치하는지 type checking 과정이 추가된 것 뿐이다. a : string = 'jongwoo'
모듈 구현과 타입 선언은 별개
d.ts
파일로 타입을 따로 정리하게 되면, 타입 선언만 이루어진다..js
파일에서는 오로지 모듈 구현만 이루어진다..ts
파일로 작성한 스크립트의 경우 모듈 구현과 타입 선언이 동시에 이루어진다.
타입스크립트는 어떻게 타입을 찾을까?
import 과정
import React from "react"; // 비상대경로
import React from "../node_modules/react" // 상대경로
상대경로
해당 파일 경로에 존재하는 .ts, .d.ts파일을 탐색한다. 해당 위치에 파일이 존재하지 않는 경우 컴파일 오류가 발생하게 된다.
비상대경로
compilerOptions.path
옵션에 설정된 패턴(모듈 이름) 과 일치한 경우 해당 경로 탐색- 현재 파일이 위치한 디렉토리에서 파일 탐색
- 루트 디렉토리(baseUrl) 옵션에 도달할 때까지 상위 디렉토리로 올라가며 파일 탐색
node_module
내부 파일 탐색node_module/[module]/package.json
의main
,types
,typing
필드에 설정된 경로 탐색- node_module/[module] 디렉토리 내의 파일 탐색
6번까지 과정에서 못찾았다면 앰비언트 모듈 선언 에서 타입 참조
- cf ) tsc —traceResolution command 확인 가능
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.js.ts' does not exist.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.js.tsx' does not exist.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.js.d.ts' does not exist.
File name '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.js' has a '.js' extension - stripping it.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.ts' does not exist.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.tsx' does not exist.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.d.ts' does not exist.
Directory '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.js' does not exist, skipping all lookups in it.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.ts' does not exist.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.tsx' does not exist.
File '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/yargs-parser/index.d.ts' does not exist.
Found 'package.json' at '/Users/oowgnoj/Desktop/tutorial/my-app/node_modules/@types/yargs-parser/package.json'.
@types/sth의 index.d.ts 는 어떻게 생겼을까?
npm install @types/underscore
node_module/@types/index.d.ts
export = React; // CommonJD and AMD module system
export as namespace React; // UMD : 전역변수로 설정
declare namespace React { //typescript 컴파일러가 알아듣게 declare namespace
//
// React Elements
// ----------------------------------------------------------------------
type temp<P = any> =
{
[K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never
}[keyof JSX.IntrinsicElements] |
ComponentType<P>;
/**
* @deprecated Please use `ElementType`
*/
type ReactType<P = any> = ElementType<P>;
type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
type JSXElementConstructor<P> =
| ((props: P) => ReactElement | null)
| (new (props: P) => Component<P, any>);
interface RefObject<T> {
readonly current: T | null;
}
type RefCallback<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"];
type Ref<T> = RefCallback<T> | RefObject<T> | null;
type LegacyRef<T> = string | Ref<T>;
....
}
Ambient Module이란?
한마디로 어디서든 사용할 수 있는 type 정의
third party library는 이 방식을 사용하고 있음
declare
ambient module에 custom 타입 추가하는 방법
export = React;
export as namespace React;
export module "react" {
import "react";
export type jongwoo = string;
}