Structural Type System vs Nominal Type System
-
Structural Type System
구조가 같으면 같은 타입으로 취급하는 방식이다.
대표적인 언어로 타입스크립트가 있다.interface IPerson { name: string; age: number; speak(): string; } type PersonType = { name: string; age: number; speak(): string; } let personInterface: Iperson = {} as any; let personType: PersonType = {} as any; personInterface = personType; // 문제 없음 personType = personInterface; // 구조가 동일하기 때문
Iperson과 PersonType은 똑같은 구조를 가지고 있기 때문에 한쪽 타입을 한쪽 타입으로 대입할 수 있다.
이러한 원리를 이용해서 타입스크립트에서는 해당 타입이 무엇인지 명시적으로 설정할 필요 없이 있던 것을 사용해도 된다. 구조가 동일하면 그냥 가져다가 쓰면 되기 때문이다.
-
Nominal Type System
구조가 같아도 이름이 다르면 다른 타입이다.
대표적인 언어로 C, Java가 있다.type PersonID = string & { readonly brand: unique symbol }; function PersonID(id: string): PersonID { return id as PersonID; } function getPersonById(id: PersonID) {} getPersonById(PersonID('id-aaaaaa'); getPersonById('id-aaaaaa'); // error: 아무 문자열이나 넣을 수 없고 PersonID 형식으로 치환된 타입만 넣을 수 있다.
-
Duck Typing
런타임에 발생하는 타이핑방식이다.
만약 어떤 새가 오리처럼 걷고, 헤엄치고, 소리를 낸다면 우리는 그 새를 오리라고 부를 것이다. 라는 철학을 가지고 만든 것이다.
대표적으로 Python이 있다.class Duck: def sound(self): print u"꽥꽥" class Dog: def sound(self): print u"멍멍" def get_sound(animal): animal.sound() def main(): bird = Duck() dog = Dog() get_sound(bird) get_sound(dog)
타입 호환성 (Type Compatibility)
- 서브타입
-
같거나 서브타입인 경우에는 할당이 가능하다. 이러한 것을 공변이라고 부른다.
// primitive type let sub7: string = ''; let sup7: string | number = sub7;
sup7은 string과 number의 조합이기 때문에 sub7보다 더 넓은 개념이다. 따라서 sub7을 넣을 수 있다. 이것이 공변이다.
// object - 각각의 프로퍼티가 대응하는 프로퍼티와 같거나 서브타입이어야 한다. let sub8: { a: string; b: number } = { a: '', b: 1 }; let sup8: { a: string | number; b: number } = sub8;
a끼리 비교하고 b끼리 비교했을 때, sup8의 a가 더 넓은 개념을 가진다. 따라서 sub8을 sup8에 넣을 수 있다.
// array - object와 마찬가지 let sub9: Array<{ a: string; b: number }> = [{ a: '', b: 1 }]; let sup9: Array<{ a: string | number; b: number }> = sub9;
-
- 슈퍼타입
- 함수의 매개변수 타입만 같거나 슈퍼타입인 경우 할당이 가능하다. 이것을 반변이라고 부른다.
class Person {} // 가장 적다. 최상위 class Developer extends Person { coding() {} } // 두번째로 많다. class StartupDeveloper extends Developer { burning() {} } // 안에 들은 함수가 가장 많다. 최하위 // 인자 f에 함수가 들어간다. Developer를 인자로 받고 Developer를 리턴하는 형태 function tellme(f: (d: Developer) => Developer) {} // Developer => Developer에다가 Developer => Developer를 할당하는 경우 tellme(function dToD(d: Developer): Developer { return new Developer(); }); // Developer => Developer에다가 Person => Developer를 할당하는 경우 tellme(function pToD(d: Person): Developer { // Person이 슈퍼타입인 경우 return new Developer(); }); // Developer => Developer에다가 StartupDeveloper => Developer를 할당하는 경우 tellme(function sToD(d: StartupDeveloper): Developer { // StartupDeveloper 서브타입 return new Developer(); });
tellme에 인수 Developer와 Person이 들어왔을 때는 문제가 없다. Developer와 Developer는 같고 Person은 Developer보다 상위이기 때문이다.
인수가 StartupDeveloper는 코드 자체에는 문제가 없다. 그러나 해당 코드를function tellme~~
코드에 넣었을 때 f에 맞지 않다. StartupDeveloper는 Developer보다 하위이기 때문에 해당 코드의 f는 burning()을 모른다. 그렇기에 논리적으로 문제가 있다.
하지만, 타입스크립트는 해당 부분에 대해서 사용자에게 선택을 준다. -
strictFunctionTypes
해당 옵션을 키면, 함수를 할당할 때 함수의 매개변수 타입이 같거나 슈퍼타입이 아닌 경우(서브타입인 경우)에 에러를 통해서 경고한다.
strictFunctionTypes 옵션을 키지 않으면 해당 코드 정도는 에러가 발생하지 않는다. (융통성을 준달까)
- 함수의 매개변수 타입만 같거나 슈퍼타입인 경우 할당이 가능하다. 이것을 반변이라고 부른다.
타입 별칭(별명) (Type Alias)
어떤 타입에 이름을 붙여준 것이다.
Interface와 비슷하지만 다르다.
Primitive Type, Union Type, Tuple, Function 등 어떤 형태의 타입을 길게 작성하지 않고 따로 빼서 이름을 만들어서 사용하는 것이다.
만들어진 타입의 별명(refer)으로 사용하는 것이지 타입을 만드는 것은 아니다.
-
Aliasing Primitive
Primitive Type을 다른 이름으로 불러 보는 것이다.
별다른 의미는 없다..type MyStringType = string; const str = 'world'; let mystr: MyStringType = 'hello'; mystr = str;
-
Aliasing Union Type
유니온 타입은 A도 가능하고 B도 가능한 타입이다.
길게 쓰는걸 짧게 쓸 수 있고 반복되는 것을 줄여준다.// 사용 x let person: string | number = 0; person = 'Mark'; // 사용 o type StringOrNumber = string | number; let another: StringOrNumber = 0; another = 'Anna';
-
Aliasing Tuple
튜플 타입에 별칭을 줘서 여러군데서 사용할 수 있게 한다.
반복과 타이핑을 줄여준다.let person: [string, number] = ['Mark', 35]; // 사용 o type PersonTuple = [string, number]; let another: PersoonTuple = ['Anna', 24];
-
Aliasing Fuction
매개변수를 별명을 만들어서 사용해준다.
type EatType = (food: string) => void;
-
Aliasing과 Interface 구분
어떤 타입이 목적이나 존재가치나 명확하면 interface.
그렇지 않고, 어떤 대상을 가리키거나 별명으로서만 존재하면 type aliasing.
Comments