const a: number = 5; // 변수 이름 뒤에 : 타입 (소문자)
const b: string = '5';
const c: boolean = true;
const d: undefined = undefined;
const e: null = null;
const f: any = 123; // 모든타입이 다 됨.
const g: true = true; // 값을 고정
const h: 5 = 5; //숫자 고정
// function 함수
function add(x: number, y: number) // 매개변수 부분의 타입 지정
: number { return x+y }; // return 부분의 타입 지정 :
// type으로 타입을 선언하는 방식 (type alias)
type Add = (x: number, y: number) => number;
const add: (x: number, y: number) => number = (x, y) => x + y;
//화살표함수
const add: Add = (x,y) => x + y; // 리턴값이 화살표 뒤에 나옴
// 객체
const obj:
{ lat: number, lon: number}
= {lat: 37.5, lon: 127.5};
// 배열
const arr: string[] = ['123', '456']
const arr2: number[] = [123, 456]
const arr3: Array<number> = [123, 456] // Generic Type
const arr4: [number, number, string] = [123, 456, 'hello'] // 길이 고정
const b: string = '5'
-> b는 5라는 문자열, 하지만 타입을 string으로 적어줄 경우 b가 5가 아닌 문자열이라는 타입으로 범위가 넓어진다. ( 더 부정확해지는 것 )
아래의 타입코드를 자바스크립트로 변환하면 타입코드는 전부 사라짐 (bold처리)
//before (ts)
const f: true = true;
type Add = () => number;
interface Minus {}
Array<string>
function add(x: number, y: number): number; // 타입 설정
function add(x, y) { // 실제 코드 선언
return x + y;
}
//after (js)
const f = true;
function add(x, y) { // 실제 코드 선언
return x + y;
}
// 문자열 형식을 억지로 다른 타입으로 바꿈
// as를 사용해서 앞의 타입을 강제로 다른 타입으로 바꿔줌
let aa = 123;
aa = 'hello' as unknown as number;
.ts ->
function add(x: number, y:number) { return x + y};
.js ->function add(x, y) { return x+y };
https://ui.toast.com/weekly-pick/ko_20220323
const array:never[] -> array
에는 아무 타입도 올 수 없다. 그래서 빈 배열을 선언할 때는 반드시 타입을 지정해줘야 함try {
const array: string[] = []; // 타입 지정
array[0];
} catch(error) {
error;
}
type World = "world";
const a: World = 'world';
const b = `hello ${a}`;
// 타입에서도 사용가능
type Greeting = `hello ${World}`; // "hello world"
type World = "world" | 'hell';
type Greeting = `hello ${World}`;
// 'hello hell', 'hello world' 타입추천을 정교하게
const c : Greeting = 'hello hell'| 'hello world'
let arr: string[] = [];
let arr2: Array<string> = [];
function rest(a, ...args: string[]) { // 타입 추가
console.log(a, args);
}
rest('1','2','3'); // 1, [2,3]
const tuple: [string, number] = ['1', 1];
// 에러처리 o
tuple[2] = 'hello';
// 에러처리 x
tuple.push('hello');
// enum
const enum EDirection {
Up = 3,
Down = 5,
Left = 4,
Right = 6,
}
// 만약 값을 지정하지 않았다면 a = 0
const a = EDirection.Up; // a = 3
// object
const ODirection = {
Up: 0,
Down: 1,
Left: 2,
Right: 3,
} as const;
// as const가 없으면 ->
// Up: number; Down: number; Left: number; Right: number;
// as const -> 할당한 값을 그대로 사용(정확한 값이 들어감)
enum | object |
---|---|
- 자바스크립트에 코드를 남기고싶지않을때 사용 | - 자바스크립트에 코드를 남기고싶을떄 사용 |
- 자바스크립트에서 코드가 사라짐 | 자바스크립트에서 코드가 남아있음 |
값을 지정해줄수 있음 (=) | 값을 지정해줄수 있음 (:) |
const obj = { a: '123', b: 'hello', c: 'world'};
// a,b,c만 꺼내오고싶을떄
// typeof : 자바스크립트 값을 type으로 쓰고싶을떄 typeof을 사용
// keyof : 키값만 받아옴
type Key = keyof typeof obj; // type Key = "a" | "b" | "c"
typeof obj 는 obj 객체의 타입을 추론 { a: string, b: string, c: string }
keyof typeof obj는 typeof obj 타입의 모든 속성 키를 유니온 타입으로 추출
a | b | c
const obj = { a: '123', b: 'hello', c: 'world'} as const;
type Key = typeof obj[keyof typeof obj];
// type Key = "123" | "hello" | "world" // value들만 가져옴
typeof obj = { readonly a: '123', readonly b: 'hello', readonly c: 'world' }
keyof typeof obj = 'a' | 'b' | 'c'
typeof obj[keyof typeof obj] = '123' | 'hello' | 'world'
모든 속성이 다 있어야한다
type A = { hello: 'world' } & { zero: 'cho' };
const a: A = { hello: 'world', zero: 'cho'};
하나만 있어도 된다.
type A = { hello: 'world' } | { zero: 'cho' };
const a: A = { hello: 'world'}; // 가능
type Animal = { breath: true };
type Poyouryu = Animal & { breed: true };
type Human = Poyouryu & { think: true};
const zerocho: Human = { breath: true, breed: true, think: true };
interface A { breath: true}
interface B extends A { breed: true } // 확장
const b: B = { breath: true, breed: true };
인터페이스 특징
interface A { talk: () => void; }
interface A { eat: () => void; }
interface A { shit: () => void; }
const a: A = { talk() {}, eat() {}, shit() {}}
Naming Rule
- 예전에는 타입 지정 변수 앞에 대문자로 I,T,E 처럼
interface
,type
,enum
을 구분지어줬는데 이젠 IDE에 다 나오기 때문에 거의 안붙임
type A = string | number; // 넓은 타입
type B = string; // 좁은 타입
# 객체
type A = { name: string };
type B = { age: number};
# 넓은 타입
type AB = A | B;
# 객체는 상세할수록 좁음 ( A & B );
type C = { name: string, age: number };
const ab: AB = { name: 'zerocho'};
const c: C = {name: 'zerocho', age: 29};
# 잉여속성검사때문에 좁은타입에서 넓은타입에 대입해도 오류가 날수있다.
# 데이터를 변수로 뺴주고 대입하면 에러가 사라짐
const obj = { name: 'zerocho', age: 29, married: false};
const c: C = obj;
function a() { // function a(): void 로 추론
}
const b = a(); // const b: void 로 추론
# 리턴값이 있으면 에러가 뜸 (undefined 가능, null 불가능)
# return을 안적거나, return만 적거나 undefined
function a(): void {
return '3'; // 에러 : 'string' 형식은 'void' 형식에 할당할 수 없습니다.
}
interface Human {
talk: () => void; // talk 메서드
}
const human: Human = {
talk() {} // talk() {return 'abc'} -> 가능
}
void 3가지
- return 값이 void
-> (함수에 직접적인 리턴값이 void인 경우에만 return에 값을넣었을떄 오류)- 매개변수에 void함수
-> (리턴값이 존재할수 있음, 리턴값을 무시)- 메서드가 void함수
-> (리턴값이 존재할수 있음, 리턴값을 무시)
function a(): void { // function 선언 void
}
function a(callback: () => void): void { // 매개변수로 선언한 void
}
interface Human {
talk: () => void; // 메서드로 선언할떄 void 두개의 역할이 조금 다름
}
declare
forEach 선언을 다른 파일에서했을때, declare를 사용하면,
forEach 외부에서 선언했음을 보증declare function forEach<T>(arr: T[], callback: (el: T) => undefined): void; // declare function forEach<T>(arr: T[], callback: (el: T) => void): void; let target: number[] = []; forEach([1, 2, 3], el => target.push(el));
interface A {
talk: () => void;
}
const a: A = {
talk() { return 3; }
}
# unknown vs any
# any 를 사용하면 이후로 타입스크립트가 타입검사를 포기함
const b: any = a.talk();
b.method();
# unknown 을 사용하면 사용자가 직접 b의 타입을 정해줌. 정해진 타입만 사용가능
const b: unknown = a.talk();
(b as A).talk();
# unknown 예)
try {
} catch (error) { // var error: unknown
error.message // -> (error as Error).message
}
function numOrStr(a: number | string) {
if (typeof a === 'string') {
a.split(',');
} else {
a.toFixed(1);
}
}
function numOrNumArr(a: number | number[]) {
if (Array.isArray(a)) { // number[]
a.slice(1);
} else { // number
a.toFixed(1);
}
}
numOrNumArr(123);
numOrNumArr([1, 2, 3]);
# 클래스 자체의 타입은 typeof 클래스(typeof A)입니다.
class A {
aaa() {}
}
class B {
bbb() {}
}
function aOrB(param: A | B) {
if (param instanceof A) { // Class 간에는 서로 instanceof 로 구별한다
param.aaa();
}
}
aOrB(new A());
aOrB(new B());
type B = { type: 'b', bbb: string };
type C = { type: 'c', ccc: string };
type D = { type: 'd', ddd: string };
type A = B | C | D;
# 값으로 구분
function typeCheck(a: A) {
if (a.type === 'b') {
a.bbb;
} else if (a.type === 'c') {
a.ccc; // 타입추론 : (parameter) a: C
} else {
a.ddd;
}
}
# 속성명으로 구분
function typeCheck(a: A) {
if ('bbb' in a) { // in 연산자 // a객체안에 bbb라는 속성이 있으면
a.type; // a: B
} else if ('ccc' in a) {
a.ccc;
} else {
a.ddd;
}
}
# 객체에 태그(라벨)을 달아놓는 습관 중요, 타입검사할떄 편함
# 객체들간 구별할때 2가지 방식을 사용
(1)
const human = { type: 'human' };
(2)
const human = { talk()};
if ('talk' in a) {
}
# 리턴값에 is가 들어가있으면 커스텀 타입가드 함수이다
function catOrDog(a: Cat | Dog): a is Dog {
# 타입 판별을 직접 만들기 ( a 에 meow라는 속성이있으면 false, 그렇지 않으면 true )
if ((a as Cat).meow) { return false }
return true;
}
const cat: Cat | Dog = { meow: 3 }
if (catOrDog(cat)) {
console.log(cat.meow);
}
if ('meow' in cat) {
console.log(cat.meow);
}
const isRejected = (input: PromiseSettledResult<unknown>):
input is PromiseRejectedResult => input.status === 'rejected';
const isFulfilled = <T>(input: PromiseSettledResult<T>):
input is PromiseFulfilledResult<T> => input.status === 'fulfilled';
const promises = await Promise.allSettled
([Promise.resolve('a'), Promise.resolve('b')]);
const errors = promises.filter(isRejected);
# {}, Object: 모든 타입(null, undefined 제외)
빈객체 {}
const x: {} = 'hello';
# 대문자 Object
const y: Object = 'hi';
# 객체 ( 객체 지양, 대신 interface, type, class 사용하기)
const xx: object = 'hi';
const yy: object = { hello: 'world' };
const z: unknown = 'h1';
# 버전 4.8 unknown : 모든값을 다 받을수있음 unknown = {} | null | undefined
// 과거에는 unknown인 변수를 if문안에 넣으면 그대로 unknown이 나옴
// 4.8 버전부터는 unknown인 변수를 if문안에 넣으면 unknown = {} | null | undefined
if (z) {
z; // {}
} else {
z; // null | undefined 여기에 속함
}
interface A {
readonly a: string;
b: string;
}
const aaaa: A = {a: 'hello', b: 'world'};
# 에러 -> 읽기 전용 속성이므로 'a'에 할당할 수 없습니다.
aaaa.a = '123';
# 어떤 키든 전부다 같은 속성으로 지정가능
type A = { [key: string]: string };
const aaaa: A = { a: 'hello', b: 'world' };
type B = 'Human' | 'Mammal' | 'Animal';
# key 가 B의 3중 하나 (키 줄이기)
type A = { [key in B]: number };
const aaaa: A = { Human: 123, Mammal: 5, Animal: 7 };
type A = { [key in B]: B };
const aaaa: A = { Human: 'Animal', Mammal: 'Human', Animal: 'Mammal' };
class A {
a: string;
b: number;
constructor(a: string, b: number = 123) {
this.a = a;
this.b = b;
}
method() {
}
}
# 2번쨰 인수의 기본값이 이미 지정되어있기떄문에 필수아님 (2번쨰 인수 지정하면 덮어씀)
const a = new A('123');
constructor : 생성자의 매개변수를 받을 수 있음
type AA = A;
const a: A = new A('123');
const b: typeof A = A;
# implements, private, protected 타입스크립트에 있는 키워드
# class 구현, interface 추상
# class는 interface를 따라야함 -> a, b속성
interface A {
readonly a: string;
b: string;
}
class B implements A {
# class의 모양을 interface에서 통제가능
a: string = '123';
b: string = 'world';
}
class C extends B {}
new C().a;
new C().b;
# 자바스크립트로 바꿧을떄
class B{
constructor() {
this.a = '123';
this.b = 'world';
}
}
class C extends B {
}
new C().a;
new C().b;
interface A {
readonly a: string;
b: string;
}
# private, protected : 객체지향에서 사용
class B implements A {
private a: string = '123';
protected b: string = 'world';
c: string = 'wow';
method() {
console.log(this.a); // o
console.log(this.b); // o
console.log(this.c); // o
}
}
class C extends B {
console.log(this.a); // x
console.log(this.b); // o
console.log(this.c); // o
}
# instance
new C().a; // x
new C().b; // x
new C().c; // o
// abc(...args: number[]) -> 전부다 받고싶을떄 이거씀
function abc(a: number, b?: number, c: number?) {}
abc(1) // o
abc(1, 2) // o
abc(1, 2, 3) // o
let obj: { a: string, b?: string } = { a: 'hello', b: 'world' } // b 필수 x
obj = { a: 'hello' };
# 같은 타입은 같은 알파벳으로 지정
function add<T>(x: T, y: T): T { return x + y }
add<number>(1, 2);
add(1, 2);
add<string>('1', '2');
add('1', '2');
add(1, '2');
# 타입에 제한을 두고싶을떄 -> T에 extends를 붙이면 T가 제한됨
function add<T extends string>(x: T, y: T): T { return x + y }
function add<T extends string | number>(x: T, y: T): T { return x + y }
function add<T extends number, K extends string>(x: T, y: K): T { return x + y }
function add<T extends {a: string}>(x: T): T {return x};
add({a: 'hello'})
function add<T extends string[]>(x: T): T {return x};
add(['1', '2', '3'])
콜백함수 형태를 제한
function add<T extends (a: string) => number>(x: T): T { return x};
add((a) => +a)
// <T extends {...}> // 특정 객체
// <T extends any[]> // 모든 배열
// <T extends (...args: any) => any> // 모든 함수
// <T extends abstract new (...args: any) => any> // 생성자 타입
// <T extends keyof any> // string | number | symbol
const a = (b = 3, c = 5) => { // const a = (기본값) => {
return '3';
}
const a = (b: number = 3, c: number =5) => {
return '3';
}
# 매개변수의 기본값 객체
const a = (b: { children: string } = {children: 'zerocho'}) => {
}
# 리액트 .jsx에서 <T> 사용시 에러가 날수있으니, 기본값 | extend 설정해주기
const add = <T = unknown>(x: T, y: T): T => { { x, y} };
const result - add(1,2);
참고자료 : 제로초 ts-all-in-one