TypeScript
20210505 TypeSciprt 02 TS에서 활용하는 type(Object, Array, Tuple, Any, Unknown, Never, Void)
TypeScript02
Object
- 일반적으로 실제 값을 갖는게 아닌 값을 가진 곳을 가르키는 정보를 가짐
- TS에서 object는 다른 의미로 사용됨
- object type는 primitive가 아닌 type이라고 함
- 즉, oject type <-> primitive type
object literal를 활용하여 만드는 경우
- object가 아닌
object literal type
임, 지정한 타입 그대로가 타입임 - literal 모양으로 type을 표현
const person1 = { name: "Tom", age: 26 };
//person1 의 type은 object가 아님
// person1은 "{name: string, age: number}" 타입 임
Object 인 전역 내장 객체를 활용하여 만드는 경우
- object type이거나 null 인 인자를 받음
- 들어오는 인자는
null
또는 primitive 가 아닌object type
이어야 함
const person2 = Object.create({ name: "jerry", age: 28 });
- object type에는 string, bool, number, symbol, null, undefined, bigint 는 넣을 수 없으므로 해당 primitive를 제한하고 싶을 때 사용
let obj2: object = {};
obj2 = { name: "tom" };
{
} // (O)
obj2 = [{ name: "tom" }]; // (O)
// array도 object의 일종이라서 넣을 수 있음
ogj2 = "string"; // (X)
ogj2 = 12; // (X)
// 등등..
Array
- js에서 array는 객체임
- Array의 경우 공통의 type으로 묶는게 좋음
- 사용방법 :
Array<타입>
또는타입[]
타입[]
let list: number[] = [1, 2, 3];
let list2: (number | string)[] = [1, 2, 3, "4"]; // union 활용 가능
Array<타입>
(충돌 가능성이 있어서 자제)
let list1: Array<number> = [1, 2, 3];
Tuple
- 각 인덱스마다 type을 줄수 있음 (길이도 일치해야 함)
- 즉, 순서 길이 모두 일치 해야함
let x: [string, number];
x = ["hello", 39];
const person: [string, number] = ["Tom", 25];
// 잘못된 사용
x = [35, "Not good"]; // 순서 error
x[2] = "word"; // 길이 error
x = ["hello"]; // 길이 error
const [first, second, third] = person; // third에는 받아올 수 없음
any
- 어떤것이 될지 모르기 때문에 어떤 것이든 할당 가능하다. 라는 느낌
- return type 지정
- 최대한 쓰지 않는게 좋음 -> 컴파일 타임에 타입체크가 정상적으로 이뤄지지 않기 때문에
- 그래서 컴파일 옵션중 any를 명확히 써줘야 하는데 그렇지 않으면 오류를 뱉도록 하는 옵션인
noImplicitAny
라는 옵션이 있음 (strict 옵션에 포함되서 켜짐) - any는 계속해서 개체를 통해 전파 됨 (편의는 타입 안전성을 잃는 대가로 오는 것임)
const returnAny = (message: any): any => {
console.log(message);
};
const any1 = returnAny("아무거나");
any1.toString(); // toString도 any가 됨
let looselyTyped: any = {};
const d1 = looselyTyped.a.b.c.d.e; // 계속해서 any로 아무거나 올수 있게 됨
const leakingAny = (obj5: any) => {
const a5: number = obj5.num;
// number로 제한을 해줘야 나중에 맞지 않는 함수인지 check 할수 있음 (number 명시 안하면 any로 전파되서 적절한 함수의 사용이 되었는지 check를 못함)
const b5 = a5 + 1;
return b5;
};
const c5 = leakingAny({ num: 0 }); // c5는 any가 됨
// c5.indexOf(0) // number는 indexOf가 없으므로 오류로 잡힘
unknown
- 응용 프로그램을 작성할 때 모르는 변수의 타입을 묘사해야하는 경우
- type적으로 누수를 줄이기 위해서
- 동적 콘텐츠로 부터 오기도 함 (사용자로부터, 또는 API의 모든 값을 의도적으로 수락하기를 원할 수 있음)
- 컴파일러와 미래의 코드를 읽는 사람에게 이 변수가 무엇이든 될 수 있음을 알려주고 싶을 때
- unknown의 경우 무조건 한정 되어야 사용할 수 있음 (바로 직접적으로 할당 불가함)
- any 보다 type safe함
- 컴파일러가 타입을 추론할 수 있게끔 타입의 유형을 좁히거나, 타입을 확정안해주면 다른곳에 할당 할 수 없고, 사용 불가함
- runtime error를 줄일 수 있음
- any 대신 unknown을 사용하도록 하여야 함
declare const maybe: unknown;
const aNumber: number = maybe // Error 바로 할당 불가
Type Guard
- runtime 때 타입을 한정 시킴
if (maybe === true) {
// if를 통해서 추론할 수 있게 타입 유형을 좁혀줌
const aBoolean: boolean = maybe; // 앞의 조건에 맞게 알아서 값을 maybe에 유추해서 넣어줌 (number)
const atring: string = maybe; // Error
}
if (typeof maybe === "string") {
const atring: string = maybe; // 앞의 조건에 맞게 알아서 값을 maybe에 유추해서 넣어줌 (string)
const aBoolean: boolean = maybe; // Error
}
never
- return에 사용되는 type
- 어떠한 형태도
return 되지 않거나
,항상 오류를 출력
함을 의미 (무한 루프) - never 타입은 모든 타입의
subtype
이며, 모든 타입에 할당 할수 있음 - 하지만 , never에는 그 어떤 것도 할당 할 수 없음 (any도 불가능 함)
- 잘못된 타입을 넣는 실수를 막고자 할 때 사용하기도 함
- 함수의 바디 부분이 끝나지 않아야 함
const error = (message: string): never => {
throw new Error(message);
};
const fail = () => {
return error('failed');
};
const infiniteLoop = (): never => {
while (true) {}
};
let a6: string = 'hello';
declare const b6: string | number;
if (typeof a6 !== 'string') {
a6; // string인데 string이 아닌 경우니까 never로 간주됨
}
if (typeof b6 !== 'string') {
b6; // 나머지인 number가 나옴
}
void
- return type으로서 사용됨
- return 값이 없으므로 어떻게 활용하지 않겠다를 명시적으로 표현하고 막는 행위라고 볼 수 있음
undefined
만 return 값 (void
)으로 할당 가능함
const returnVoid = (message: string) => {
console.log(message);
return undefined;
// return; 이어도 상관 X, return이 없어도 상관x
};
const r = returnVoid("no return"); // X (잘못된 사용)
returnVoid("no return"); // O (이게 잘 사용한 것임)