ν°μ€ν 리 λ·°
πΆ μμ±μμ μ¬μ©μμ κ΄μ μΌλ‘ μ½λ λ°λΌλ³΄κΈ°
Type System
νμ μμ€ν μλ λ€μκ³Ό κ°μ λ κ°μ§μ μμ€ν μ΄ μλ€.
- μ»΄νμΌλ¬μκ² μ¬μ©νλ νμ μ λͺ μμ μΌλ‘ μ§μ
- μ»΄νμΌλ¬κ° μλμΌλ‘ νμ μ μΆλ‘
TypeScriptμ JavaScriptμ Type System
νμ
μ€ν¬λ¦½νΈλ λ κ°μ§ μμ€ν
λͺ¨λ κ°λ₯νλ° κΈ°λ³Έμ μΌλ‘ νμ
μ λͺ
μμ μΌλ‘ μ§μ ν μ μκ³ μ§μ νμ§ μμΌλ©΄ νμ
μ€ν¬λ¦½νΈ μ»΄νμΌλ¬κ° μλμΌλ‘ νμ
μ μΆλ‘ νλ€.
νμ
μ ν΄λΉ λ³μκ° ν μ μλ μΌμ κ²°μ νλλ° μλ°μ€ν¬λ¦½νΈλ ν¨μ μ¬μ©λ²μ λν μ€ν΄λ₯Ό μΌκΈ°νλ€.
μλ₯Ό λ€μ΄ μ΄λ€ ν¨μ μμ λ§€κ°λ³μκ° numberνμ
μ΄μ΄μΌ νλλ° stringμ μ
λ ₯νλ©΄ NaNμΌλ‘ μΆλ ₯μ΄ λλ€.
μ¦, μ¬μ©μμκ² μ€λ₯κ° μλ€λ κ²μ μλ €μ£Όμ§ μλλ€.
// JavaScript
// (f2 μ€νμ κ²°κ³Όκ° NaN μ μλν κ²μ΄ μλλΌλ©΄)
// μ΄ ν¨μμ μμ±μλ λ§€κ°λ³μ a κ° number νμ
μ΄λΌλ κ°μ μΌλ‘ ν¨μλ₯Ό μμ±νμ΅λλ€.
function f2(a) {
return a * 38;
}
// μ¬μ©μλ μ¬μ©λ²μ μμ§νμ§ μμ μ±, λ¬Έμμ΄μ μ¬μ©νμ¬ ν¨μλ₯Ό μ€ννμ΅λλ€.
console.log(f2(10)); // 380
console.log(f2('Mark')); // NaN
TypeScriptμ μΆλ‘
νμ
μ€ν¬λ¦½νΈλ νμ
μ΄ λͺ
μμ μΌλ‘ μ§μ λμ§ μμΌλ©΄ μΆλ‘ μ νκ² λλ€.
μλ₯Ό λ€μ΄ μ΄λ€ ν¨μ μμ λ§€κ°λ³μμ νμ
μ΄ μ§μ λμ§ μμλ€λ©΄ anyλ‘ μΆλ‘ νλ€.
// νμ
μ€ν¬λ¦½νΈ μ½λμ§λ§,
// a μ νμ
μ λͺ
μμ μΌλ‘ μ§μ νμ§ μμ κ²½μ°μ΄κ° λλ¬Έμ a λ any λ‘ μΆλ‘ λ©λλ€.
// ν¨μμ λ¦¬ν΄ νμ
μ number λ‘ μΆλ‘ λ©λλ€. (NaN λ number μ νλμ
λλ€.)
function f3(a) {
return a * 38;
}
// μ¬μ©μλ a κ° any μ΄κΈ° λλ¬Έμ, μ¬μ©λ²μ λ§κ² λ¬Έμμ΄μ μ¬μ©νμ¬ ν¨μλ₯Ό μ€ννμ΅λλ€.
console.log(f3(10)); // 380
console.log(f3('Mark') + 5); // NaN
nolmplicitAny
νμ§λ§ μ΄λ μνν μμκ° λ μ μμΌλ©° μ΄λ₯Ό λ°©μ§νκΈ° μν μ΅μ
nolmplicitAnyμ΄ μλ€.
νμ
μ λͺ
μνμ§ μμ κ²½μ° νμ
μ€ν¬λ¦½νΈκ° anyλΌκ³ μΆλ‘ νκ² λλ©΄ μ»΄νμΌ μλ¬λ₯Ό λ°μμμΌ νμ
μ μ§μ νλλ‘ μ λνλ μ΅μ
μ΄λ€.
νμ
μ λͺ
μν΄μ£Όμ§ μμΌλ©΄ error TS7006: parameter 'a' implicitly has an 'any' type μ΄λΌλ μλ¬κ° λ¬λ€.
μ¦, μμ±μκ° νμ
μ μ§μ ν΄μ€ κΈ°νλ₯Ό λΆμ¬ν΄ μ¬μ©μμκ² μλ¬κ° λ°μνμ§ μλλ‘ νλ€.
// error TS7006: Parameter 'a' implicitly has an 'any' type.
function f3(a) {
return a * 38;
}
// μ¬μ©μμ μ½λλ₯Ό μ€νν μ μμ΅λλ€. μ»΄νμΌμ΄ μ μμ μΌλ‘ λ§λ¬΄λ¦¬ λ μ μλλ‘ μμ ν΄μΌ ν©λλ€.
console.log(f3(10));
console.log(f3('Mark') + 5);
numberλ‘ μΆλ‘ λ return νμ
// λ§€κ°λ³μμ νμ
μ λͺ
μμ μΌλ‘ μ§μ νμ΅λλ€.
// λͺ
μμ μΌλ‘ μ§μ νμ§ μμ ν¨μμ λ¦¬ν΄ νμ
μ number λ‘ μΆλ‘ λ©λλ€.
function f4(a: number) {
if (a > 0) {
return a * 38;
}
}
// μ¬μ©μλ μ¬μ©λ²μ λ§κ² μ«μνμ μ¬μ©νμ¬ ν¨μλ₯Ό μ€ννμ΅λλ€.
// ν΄λΉ ν¨μμ λ¦¬ν΄ νμ
μ number μ΄κΈ° λλ¬Έμ, νμ
μ λ°λ₯΄λ©΄ μ΄μ΄μ§ μ°μ°μ λ°λ‘ ν μ μμ΅λλ€.
// νμ§λ§ μ€μ undefined + 5 κ° μ€νλμ΄ NaN μ΄ μΆλ ₯λ©λλ€.
console.log(f4(5)); // 190
console.log(f4(-5) + 5); // NaN
μμ μ½λμμ λ¦¬ν΄ νμ
μ΄ μ§μ λμ§ μμκ³ f4(-5)λ undefinedμΈλ° νμ
μ€ν¬λ¦½νΈμμ numberλ‘ μΆλ‘ μ νλ€.
μ΄λ₯Ό ν΅ν΄ κΈ°λ³Έμ μΌλ‘ numberμμ undefinedκ° ν¬ν¨λμ΄ μμμ μ μ μλ€.
strictNullChecks
λ°λΌμ strictNullChecks μ΅μ
μ μΌμ λͺ¨λ νμ
μ μλμΌλ‘ ν¬ν¨λμ΄ μλ nullκ³Ό undeο¬nedλ₯Ό μ κ±°ν μ μλ€.
μ΄ μ΅μ
μ μΌλ©΄ λ€μκ³Ό κ°μ΄ f4(-5)λΆλΆμμ μλ¬κ° λλ€.
// λ§€κ°λ³μμ νμ
μ λͺ
μμ μΌλ‘ μ§μ νμ΅λλ€.
// λͺ
μμ μΌλ‘ μ§μ νμ§ μμ ν¨μμ λ¦¬ν΄ νμ
μ number | undefined λ‘ μΆλ‘ λ©λλ€.
function f4(a: number) {
if (a > 0) {
return a * 38;
}
}
// μ¬μ©μλ μ¬μ©λ²μ λ§κ² μ«μνμ μ¬μ©νμ¬ ν¨μλ₯Ό μ€ννμ΅λλ€.
// ν΄λΉ ν¨μμ λ¦¬ν΄ νμ
μ number | undefined μ΄κΈ° λλ¬Έμ,
// νμ
μ λ°λ₯΄λ©΄ μ΄μ΄μ§ μ°μ°μ λ°λ‘ ν μ μμ΅λλ€.
// μ»΄νμΌ μλ¬λ₯Ό κ³ μ³μΌνκΈ° νκΈ° λλ¬Έμ μ¬μ©μμ μμ±μκ° μλ
Όμ ν΄μΌν©λλ€.
console.log(f4(5));
console.log(f4(-5) + 5); // error TS2532: Object is possibly 'undefined'
return νμ μ§μ
// λ§€κ°λ³μμ νμ
κ³Ό ν¨μμ λ¦¬ν΄ νμ
μ λͺ
μμ μΌλ‘ μ§μ νμ΅λλ€.
// μ€μ ν¨μ ꡬνλΆμ λ¦¬ν΄ νμ
κ³Ό λͺ
μμ μΌλ‘ μ§μ ν νμ
μ΄ μΌμΉνμ§ μμ μ»΄νμΌ μλ¬κ° λ°μν©λλ€.
// error TS2366: Function lacks ending return statement and return type does not incl
function f5(a: number): number {
if (a > 0) {
return a * 38;
}
}
noImplicitReturns
noImplicitReturns μ΅μ μ ν¨μ λ΄μμ λͺ¨λ μ½λκ° κ°μ 리ν΄νμ§ μμΌλ©΄ μ»΄νμΌ μλ¬λ₯Ό λ°μμν¨λ€.
// if κ° μλ κ²½μ° return μ μ§μ νμ§ μκ³ μ½λκ° μ’
λ£λλ€.
// error TS7030: Not all code paths return a value.
function f5(a: number) {
if (a > 0) {
return a * 38;
}
}
λ§€κ°λ³μμ object κ° λ€μ΄μ€λ κ²½μ°
// JavaScript
function f6(a) {
return `μ΄λ¦μ ${a.name} μ΄κ³ , μ°λ Ήλλ ${
Math.floor(a.age / 10) * 10
}λ μ
λλ€.`;
}
console.log(f6({ name: 'Mark', age: 38 })); // μ΄λ¦μ Mark μ΄κ³ , μ°λ Ήλλ 30λ μ
λλ€.
console.log(f6('Mark')); // μ΄λ¦μ undefined μ΄κ³ , μ°λ Ήλλ NaNλ μ
λλ€.
μμ μ½λλ₯Ό λ€μκ³Ό κ°μ΄ object literal typeμΌλ‘ λ°κΏμ£Όλ©΄ λκ² λ€.
function f7(a: { name: string; age: number }): string {
return `μ΄λ¦μ ${a.name} μ΄κ³ , μ°λ Ήλλ ${
Math.floor(a.age / 10) * 10
}λ μ
λλ€.`;
}
console.log(f7({ name: 'Mark', age: 38 })); // μ΄λ¦μ Mark μ΄κ³ , μ°λ Ήλλ 30λ μ
λλ€.
console.log(f7('Mark')); // error TS2345: Argument of type 'string' is not
assignable to parameter of type '{ name: string; age: number; }'.
νμ§λ§ λ§€λ² κΈΈκ² object literal typeμΌλ‘ μ°κΈ° νλ€κΈ°μ νΉμ ν νμ μΌλ‘ λ½μμ λ§λ€μ΄ λλ λ°©μμ μ°μ.
interface PersonInterface {
name: string;
age: number;
}
type PersonTypeAlias = {
name: string;
age: number;
};
function f8(a: PersonInterface): string {
return `μ΄λ¦μ ${a.name} μ΄κ³ , μ°λ Ήλλ ${
Math.floor(a.age / 10) * 10
}λ μ
λλ€.`;
}
console.log(f8({ name: 'Mark', age: 38 })); // μ΄λ¦μ Mark μ΄κ³ , μ°λ Ήλλ 30λ μ
λλ€.
console.log(f8('Mark')); // error TS2345: Argument of type 'string' is not assignable to parameter of type 'PersonInterface'.
π» 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
κ΅¬μ‘°κ° κ°μλ μ΄λ¦μ΄ λ€λ₯΄λ©΄, λ€λ₯Έ νμ μΌλ‘ μ·¨κΈνλ λ°©μμ΄λ€.
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 TS2345: Argument of type 'string' is not assignable to parameter of type 'PersonID'.
Type 'string' is not assignable to type '{ readonly brand: unique symbol; }'.
μμ μ½λμμ 보면 무쑰건 PersonIDλ‘ μΉνλ νμλ§ λ£μ΄μΌ νλ€λ κ²μ΄λ€.
νμ§λ§ μ΄ λ°©μμ μ μ¬μ©λμ§ μκ³ νμ
μ€ν¬λ¦½νΈμμλ λ°λ₯΄μ§ μλ λ°©μμ΄λ€.
duck typing
λ§μ½ μ΄λ€ μκ° μ€λ¦¬μ²λΌ κ±·κ³ , ν€μμΉκ³ , κ½₯κ½₯거리λ μ리λ₯Ό λΈλ€λ©΄ λλ κ·Έ μλ₯Ό μ€λ¦¬λΌκ³ λΆλ₯Ό κ²μ΄λ€. λΌλ λ»μ΄λ€.
λνμ μΌλ‘ νμ΄μ¬μμ μ¬μ©νλ μμ€ν
μΌλ‘ structural type systemκ³Ό λΉμ·νλ€κ³ λ³Ό μ μλ€.
νμ§λ§ νμ
μ€ν¬λ¦½νΈμμλ μ¬μ©λμ§ μλλ€.
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)
μλΈνμ
// sub1 νμ
μ sup1 νμ
μ μλΈ νμ
μ΄λ€.
let sub1: 1 = 1;
let sup1: number = sub1;
sub1 = sup1; // error! Type 'number' is not assignable to type '1'.
// sub2 νμ
μ sup2 νμ
μ μλΈ νμ
μ΄λ€.
let sub2: number[] = [1];
let sup2: object = sub2;
sub2 = sup2; // error! Type '{}' is missing the following properties from type 'number[]': length, pop, push, concat, and 16 more.
// sub3 νμ
μ sup3 νμ
μ μλΈ νμ
μ΄λ€.
let sub3: [number, number] = [1, 2];
let sup3: number[] = sub3;
sub3 = sup3; // error! Type 'number[]' is not assignable to type '[number, number]'. Target requires 2 element(s) but source may have fewer.
// sub4 νμ
μ sup4 νμ
μ μλΈ νμ
μ΄λ€.
let sub4: number = 1;
let sup4: any = sub4;
sub4 = sup4;
// sub5 νμ
μ sup5 νμ
μ μλΈ νμ
μ΄λ€.
let sub5: never = 0 as never;
let sup5: number = sub5;
sub5 = sup5; // error! Type 'number' is not assignable to type 'never'.
class Animal {}
class Dog extends Animal {
eat() {}
}
// sub6 νμ
μ sup6 νμ
μ μλΈ νμ
μ΄λ€.
let sub6: Dog = new Dog();
let sup6: Animal = sub6;
sub6 = sup6; // error! Property 'eat' is missing in type 'SubAnimal' but required in type 'SubDog'.
μμ μ½λλ€μμ λ€μκ³Ό κ°μ κ·μΉλ€μ λ°κ²¬ν μ μλ€.
1. κ°κ±°λ μλΈ νμ μΈ κ²½μ°, ν λΉμ΄ κ°λ₯νλ€. (곡λ³)
// primitive type
let sub7: string = '';
let sup7: string | number = sub7;
// object - κ°κ°μ νλ‘νΌν°κ° λμνλ νλ‘νΌν°μ κ°κ±°λ μλΈνμ
μ΄μ΄μΌ νλ€.
let sub8: { a: string; b: number } = { a: '', b: 1 };
let sup8: { a: string | number; b: number } = sub8;
// array - object μ λ§μ°¬κ°μ§
let sub9: Array<{ a: string; b: number }> = [{ a: '', b: 1 }];
let sup9: Array<{ a: string | number; b: number }> = sub8;
νμ μ€ν¬λ¦½νΈλ κΈ°λ³Έμ μΌλ‘ 곡λ³μ λ°λ₯Έλ€.
2. ν¨μμ λ§€κ°λ³μ νμ λ§ κ°κ±°λ μνΌνμ μΈ κ²½μ°, ν λΉμ΄ κ°λ₯νλ€.(λ°λ³)
class Person {}
class Developer extends Person {
coding() {}
}
class StartupDeveloper extends Developer {
burning() {}
}
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 {
return new Developer();
});
// Developer => Developer μλ€κ° StartipDeveloper => Developer λ₯Ό ν λΉνλ κ²½μ°
tellme(function sToD(d: StartupDeveloper): Developer {
return new Developer();
});
κ°μ₯ λ§μ§λ§ tellmeλΆλΆμ λ
Όλ¦¬μ μΌλ‘ μ½κ°μ λ¬Έμ κ° μλ€.
StartupDeveloperκ° Developerκ° νμνμ
μ΄κΈ° λλ¬Έμ΄λ€.
νμ§λ§ μ΅ν΅μ±μ λΆμ¬ν΄ νμ
μ€ν¬λ¦½νΈλ μλ¬λ₯Ό μλ°μμν€μ§λ§ strictFunctionTypes μ΅μ
μ μΌλ©΄ μλ¬λ₯Ό λ°μνκ² νλ€.
μ΄λ ν¨μλ₯Ό ν λΉν μμ ν¨μμ λ§€κ°λ³μ νμ
μ΄ κ°κ±°λ μνΌνμ
μΈ κ²½μ°κ° μλ κ²½μ°, μλ¬λ₯Ό ν΅ν΄ κ²½κ³ νλ€.
π« νμ λ³μΉ (Type Alias)
Interface λ λΉμ·ν΄ 보μ΄λ μ‘°κΈ λ€λ₯΄λ€.
Primitive, Union Type, Tuple, Function μ λ€λ₯Έ μ΄λ¦μΌλ‘ λΆλ₯΄κΈ° μν΄ μ¬μ©νκ² λλ€.
λ§λ€μ΄μ§ νμ
μ referλ‘ μ¬μ©νλ κ²μ΄μ§ νμ
μ λ§λλκ²μ μλλ€.
Aliasing Primitive
Primitiveλ₯Ό λ€λ₯Έ μ΄λ¦μΌλ‘ λΆλ₯΄λ κ²μ΄λ€.
μ¬μ€ λ³ μλ―Έκ° μλ€.
type MyStringType = string;
const str = 'world';
let myStr: MyStringType = 'hello';
myStr = str;
Aliasing Union Type
μ λμ¨ νμ μ A λ κ°λ₯νκ³ B λ κ°λ₯ν νμ μΌλ‘ κΈΈκ² μ°λ κ±Έ μ§§κ²νκ³ λ°λ³΅μ μ€μΈλ€λλ° μλ―Έκ° μλ€.
let person: string | number = 0;
person = 'Mark';
type StringOrNumber = string | number;
let another: StringOrNumber = 0;
another = 'Anna';
Aliasing Tuple
νν νμ μ λ³μΉμ μ€μ μ¬λ¬κ΅°λ°μ μ¬μ©ν μ μκ² νλ κ²μΌλ‘ Aliasing Union Typeκ³Ό λ§μ°¬κ°μ§λ‘ λ°λ³΅μ μ€μΈλ€.
let person: [string, number] = ['Mark', 35];
type PersonTuple = [string, number];
let another: PersonTuple = ['Anna', 24];
Aliasing Function
μ΄ λν λ°λ³΅μ μ€μ΄κ³ ν¨μμ νμ΄ν μμ μ€μ¬μ€λ€.
type EatType = (food: string) => void;
'TypeScript' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
π TypeScript Compiler (0) | 2022.12.15 |
---|---|
π Basic Types (0) | 2022.12.09 |
TypeScript μ€μΉνκΈ°π (0) | 2022.12.03 |