js
로 컴파일 하지 않는다const a = "hello" // ts가 a를 string으로 감지. Implicit type
const b: string = "hi" // 타입을 명시적으로 선언. Explicit type
type
키워드로 선언하는 타입
?
키워드로 선언하며 해당 타입이 undefined
가 될수도 있다는 의미를 가진다
interface Iobj {
name: string,
nickName?: string // nickName: string | undefined
}
읽기전용 속성, 수정이 불가하다
interface Iobj {
name: string,
readonly nickName: string
}
const someone: Iobj = { name: 'peter', nickName: 'spiderman'};
someone.nickName = 'superman' // error
각기 다른 타입의 요소를 가지는 하나의 배열
const arr: [number, string, boolean] = [1, "strong", false]
반환값이 없으면서 Error를 던지거나 실행이 종료되는 함수의 타입
function someError(message: string): never {
throw new Error(message)
}
function hello(name:string|number){
if(typeof name ==="string"){
name // string
}else if(typeof name === "number"){
name // number
}else{
name // never
}
// union 타입에서 제거가 된다
type StrUnion = never | string
// intersection 타입에서는 덮어쓴다
type NeverInter = never & string
any 처럼 모든 타입을 허용한다.
TS에서 unknown으로 추론하는 경우는 없으니 개발자가 명시해야 한다.
assertion 혹은 타입가드와 함께 사용한다.
아래 코드에선 타입가드는typeof
로 해보았다.
let a:unknown;
if (typeof a === 'number') {
let b = a + 1
}
오버로딩으로 매개변수의 타입, 개수, 순서가 달라질 수 있다.
오버로딩을 위해 다수의 call signature를 type에 등록 시킨다.
아래와 같이, 매개변수의 개수가 달라지는 경우 optional 키워드를 적용하자.
type Add = {
(a:number, b:number): number,
(a:number, b:number, c:number): number
}
const add:Add=(a,b,c?:number)=>{
if(c) return a+b+c
return a+b
}
TS는 generic을 바탕으로 call signature를 만들어 준다.
관습적으로 T, V가 많이 쓰인다.
type Player<T> = {
name: string
extraInfo: T
}
type NicoExtra = {
favFood: string
}
type NicoPlayer = Player<NicoExtra>
const nico: NicoPlayer = {
name: "nico",
extraInfo:{
favFood: "kimchi"
}
}
// 역으로 class에서 제네릭을 먼저 선언하고
// interface에서 제네릭을 내려받아(?) 사용하는 케이스
interface SStorage<T>{
[key:string]: T
}
class LocalStorage<T>
private storage: SStorage<T>
set(key:string, value:T){}
}
extends
로 상속 받을 수 있는 클래스, 인스턴스를 만들수 없는 클래스
구현된 메서드를 포함 시킬 수 있다.
abstract class User {
constructor(
private firstName: string,
private lastName: string,
private nickname: string
){}
abstract getNickName(): void
getFullName() {
return ${this.firstName} ${this.lastName}
}
}
class Player extends User{
getNickName() {
console.log(this.nickname)
}
}
const nico = new Player("nico","las","L\N");
해당 키워드로 property나 method를 선언하면
클래스의 인스턴스와 자식클래스에선 접근 할 수 없다.
마찬가지로, 클래스의 인스턴스에서는 접근 할 수 없으나
자식클래스에선 접근 할 수 있다.
type Words = {
[key: string]: string // key값을 접근할 때 string 타입도 허용
}
class Dict{
private words: Words
constructor() {
this.words={}
}
add(word: Word){ // Word 클래스를 매개변수로 받는다
if (this.words[word.term] === undefined) {
this.words[word.term] = word.def;
}
}
def(term: string){
return this.words[term]
}
}
class Word{
constructor(
public term:string,
public def:string
){}
}
const kimchi=new Word("kimchi","한국의 음식");
const dict=new Dict()
dict.add(kimchi)
dict.def("kimchi") // "한국의 음식"
abstract 클래스 안에서만 abstract method를 선언 할 수 있다.
abstract method
는 call signature 앞에 abstract
키워드를 붙여 선언한다.
abstract 클래스를 상속 받는 클래스들은 abstract method
를 구현해야 한다.
abstract class 일때
abstract class User{ constructor( protected firstName:string, protected lastName:string ){} abstract sayHi(name:string):string abstract fullName():string } class Player extends User{ fullName(){ return`${this.firstName}${this.lastName}` } sayHi(name:string){ return'Hello ${name}' } }
interface로 바꾸고 난 후
// `interface`는 `private`, `protected` 접근제어자를 사용할 수 없다. // 따라서, interface를 implements하는 클래스에서 constructor에서 public으로 property를 선언 해주어야 한다. // 하지만, js로 컴파일시 `interface`문이 사라지므로 // 번들 용량이 줄어드는 이점이 있다. interface User{ firstName: string, lastName: string, sayHi: (name:string): string, fullName: (): string } interface Human{ race: white } class Player implements User, Human{ constructor() { public firstName: string, public lastName: string, public race: string } fullName(){ return`${this.firstName}${this.lastName}` } sayHi(name:string){ return'Hello ${name}' } }
공식 문서에서도 나오는 내용이지만, object
나 class
의 타입을 정의할 때엔 interface
를 나머지는 type
을 사용하는게 권장 된다.
{
"include": ["src"], // 읽어올 파일들의 경로
"compilerOptions": {
"outDir": "build", // 컴파일시 저장되는 경로
"target": "ES6", // 컴파일후 적용되는 자바스크립트 문법의 ver.
"lib": ["ES6"], // 타입 정의가 내장된 라이브러리 ex) DOM, WebWorker
"strict": true, // strict mode
"esModuleInterop": true, // 모듈 import 할때 범용적으로 쓰임, babel과의 호환성을 위해서도
// https://it-eldorado.tistory.com/128 자세한 내용 참고
"module": "CommonJS" // Node.js 환경에서 실행되는 모듈 시스템 방식
}
}
컴포넌트 혹은 모듈의 타입을 정의 해주는 파일이다.
myPackage.js
export function init(config) {
return true;
}
export function exit(code) {
return code + 1;
}
myPackage.d.ts
interface Config {
url: string;
}
declare module "myPackage" {
function init(config: Config): boolean;
function exit(code: Number): Number;
}
# JSDOC
자바스크립트 모듈의 타입을 타입스크립트로 정의하지 않고
주석(?)을 제공하여 타입스크립트에게 타입힌트를 제공하는 API 문서 생성기이다
아래의 코드에서는 각각의 함수에 대한 call signatures를 정의 해주었다
## 작성순서
> 1. tsconfig.json
`"allowJs": true` 추가
> 2. 타입을 정의해줘야 하는 js 파일
// @ts-check
/** 작성후 enter (자동완성)
```ts
// @ts-check
/**
* Initializes the project
* @param {object} config
* @param {boolean} config.debug
* @param {string} config.url
* @returns boolean
*/
export function init(config) {
return true;
}
/**
* Exits the program
* @param {number} code
* @returns number
*/
export function exit(code) {
return code + 1;
}
type 정의를 위한 레포지터리
https://github.com/DefinitelyTyped/DefinitelyTyped