이번에는 지난 1부에 이어서 계속해서 TypeScript와 관련되어 필자가 헷갈리는 부분을 적어보고자 한다. Javascript에 있는 내용일 수도 있지만 최대한 겹치는 부분은 피하면서 적을 예정이다. 🙇♂️
아마 다음에 적을 Class같은 부분은 다른 링크를 달아두어 최대한 TypeScript와 관련된 부분만 적을 것이다. 👨💻
지난번 회고에서도 적었듯이 최대한 정확한 정보로 작성하고는 있지만 불가피하게 잘못 된 정보를 적을 수도 있다는 점 미리 양해바란다.
결론부터 말하자면 객체타입은 프로퍼티를 기준으로 호환성을 가진다.
예를 들어 Animal의 프로퍼티가 있고 Dog가 Animal의 프로퍼티를 그대로 가지고 있으면서 breed라는 프로퍼티가 더 있는 상황이라면, Dog는 Animal의 서브타입이라고 볼 수 있게 된다.
즉, 서브 타입일수록 슈퍼 타입의 속성을 그대로 가지면서 속성이 더 많아진다고 볼 수 있다.
여러개의 타입을 합성해서 새롭게 만들어낸 타입
유니언 타입은 서로 다른 두 개 이상의 타입들을 사용하여 만드는 것으로, 유니언 타입의 값은 타입 조합에 사용된 타입 중 무엇이든 하나를 타입으로 가질 수 있다. 조합에 사용된 각 타입을 유니언 타입의 멤버라고 부른다.
ex. string | number; -> 문자열 또는 숫자를 받을 수 있게 된다.
‼️유의사항 : TypeScript에서 유니언을 다룰 때는 해당 유니언 타입의 모든 멤버에 대하여 유효한 작업일 때에만 허용된다. 예를 들어 string | number라는 유니언 타입의 경우, string 타입에만 유효한 메서드는 사용할 수 없다.‼️
두 개 이상의 타입들이 공통적으로 가지고 있는 타입으로 좁혀서 만든다.
ex. number & string -> never로 만들어지게 된다.
일반적인 변수를 선언할 때 자동으로 타입을 추론해준다.
함수의 경우에는 return문 다음의 반환값을 기준으로 추론가능하다.
원하는 기능을 만들기 어려울때 {} as 타입이름 으로 간주를 시켜주면 된다!
규칙
A as B A가 B의 슈퍼타입이거나 서브타입이어야 한다.
즉, A와 B가 완전 독립적인 타입이면 안된다는 것이다.
TypeScript에는 명시적인 체크를 수행하지 않고도 타입에서 null과 undefined를 제거하는 특별한 구문이 있다. 어떤 표현식 뒤에 !를 쓰면, 이는 해당 값이 null 또는 undefined가 아니라고 타입 단언을 하는 것이다.
if(typeof a === ‘number’){ let b = a + 1} 이런식으로 typeof를 먼저 조건을 걸어주면 된다.
예를 들어 typeof로는 Date를 정확히 분류가 되지 않는다. 이럴 때 instanceof를 사용하면 Date의 객체냐 이렇게 판별을 해줄 수 있다. (클래스여야 가능! 객체 타입은 활용 불가능)
"value" in x. 여기서 "value"는 문자열 리터럴이고 x는 유니온 타입으로 가정해보자. "true" 분기는 x의 타입을 좁혀서 옵셔널 속성 또는 필수 속성 value를 가진 타입으로 좁히게 되고, "false" 분기는 optional 속성이거나 속성 value가 없는 타입으로 좁히게 된다.
ex . value && “age” in value <- value가 존재하며 value안에 age가 있는지 확인하는 구문이다.
한 줄로 정리하자면, 어떤 [타입의] 매개변수를 받고, 어떤 [타입의] 결과값을 반환하는지 보여주면 된다.
선택적 매개변수로 만드는 방법 -> ?: ex) name ?: string
Call Signatures은 타입을 만들 수 있고, 함수가 어떻게 작동하는 지 서술해 둘 수 있다.
예시 ) type Add=(a:number, b:number) ⇒number
const add:Add = (a,b) ⇒ a+b
이 방식이 좋은 이유는 프로그램을 디자인하면서 타입을 먼저 생각하고 그 다음 코드를 구현 할 수 있기 때문이다.
같은 이름의 함수를 매개변수의 개수나 타입에 따라 여러가지 버전으로 정의하는 방법이다.
여기서는 코드로 2가지의 예시를 보여주도록 하겠다.
// 버전들 -> 오버로드 시그니쳐
function func(a: number): void;
function func(a: number, b: number, c: number): void;
// 실제 구현부 -> 구현 시그니쳐
function func(a: number, b?: number, c?: number) {
if (typeof b === "number" && typeof c === "number") {
console.log(a + b + c);
} else {
console.log(a * 20);
}
}
func(1); // ✅ 버전 1 - 오버로드 시그니쳐
func(1, 2); // ❌
func(1, 2, 3); // ✅ 버전 3 - 오버로드 시그니쳐
//파라미터의 개수가 다른 경우에 overloading
type Add = {
(a:number, b: number) : number,
(a:number, b:number, c: number): number,}
const add:Add = (a,b,c) => {
return a + b} //이러면 오류가 발생하는데 c는 필수일수도 아닐수도 있기 때문에(즉, 옵션이라는 것!)
//해결방안
const add:Add = (a,b,c?:number) => {
if(c) return a+b+c
return a + b}
예를 들어 Animal이라는 타입이 있고 Dog와 Cat의 타입이 있다고 가정해보자.
type Animal = Dog | Cat
해당 타입(Dog,Cat)의 프로퍼티를 다 알고 있어야하는게 문제가 될시에 어떻게 Dog와 Cat 타입을 나눌 수 있을까? (혹은 이 이상의 타입들을 어떻게 나눌 수 있을까?)
그럴 땐 함수를 만들어서 function isDog(animal : Animal){ return (animal as Dog).isBark !== undefined;} 이런식으로 해주면 된다.
하지만 이렇게 하는데도 반환되는 type은 Animal로 되기 때문에 저 리턴하는 함수에다가 animal is Dog를 추가해줘야 한다.
function isDog(animal: Animal): animal is Dog {
return (animal as Dog).isBark !== undefined;
}
📚참고문헌
https://nomadcoders.co/typescript-for-beginners
https://www.inflearn.com/course/한입-크기-타입스크립트/dashboard
https://www.typescriptlang.org/docs/handbook/2/narrowing.html