타입을 명시적으로 지정할 수 있다.
타입을 명시적으로 지정하지 않으면, 타입스크립트 컴파일러가 자동으로 타입을 추론
타입이란 해당 변수가 할 수 있는 일을 결정합니다.
// JavaScript
// f2 실행의 결과가 NaN을 의도한 것이 아니라면
// 이 함수의 작성자는 매개변수 a 가 number 타입이라는 가정으로 함수를 작성했습니다.
function f2(a) {
return a;
}
// 사용자는 사용법을 숙지하지 않은 채, 문자열을 사용하여 함수를 실행했습니다.
console.log(f2(10)); // 380
console.log(f2('Mark')); // NaN
noImplicitAny 옵션
타입을 명시적으로 지정하지 않은 경우, 타입스크립트가 추론 중 'any' 라고 판단하게 되면, 컴파일 에러를 발생시켜 명시적으로 지정하도록 유도한다.
strictNullChecks 옵션
모든 타입에 자동으로 포함되어 있는 'null'과 'undefined'를 제거해준다.
noImplicitReturns 옵션
함수 내에서 모든 코드가 값을 리턴하지 않으면, 컴파일 에러를 발생시킨다.
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;}'.
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;
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;}'.
// type alias
type EatType = (food:string) => void;
// interface
interface IEat {
(food:string): void;
}
// type alias
type PersonList = string[];
// interface
interface IPersonList{
[index:number]:string;
}
interface ErrorHandling {
success:boolean;
error?:{ message: string };
}
interface ArtistsData {
artists: { name: string }[];
}
// type alias
type ArtistsResponseType = Artists & ErrorHandling {}
// interface
interface IArtistsResponse extends ArtistsData, ErrorHandling{}
let art : ArtistsResponseType;
let iar : IArtistsResponse;
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs():void;
}
type PetType = Bird | Fish;
interface IPet extends PetType {} // error TS2312: An interface can only extend an object type or
//intersection of object types with statically known members;
class Pet implements PetType {} // error TS2422: A class can only implement an object type or
//intersection of object types with statically known members
interface MergingInterface {
a: string;
}
interface MergingInterface {
b: string;
}
let mi: MergingInterface = { a: 'hello', b: 'world' };
다른 모듈/라이브러리의 타입을 확장하고 싶을 때 global.d.ts 생성 후 namespace 안에서 사용
let sub1: 1 = 1;
let sup1: number = sub1;
sub1 = sup1; // error Type 'number' is not assignable to type '1';
let sub2: number[] = [1];
let sup2: object = sub2;
sub2 = sup2; // error Type 'number[]' is not assignable to type '{number,number}'
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 lower.
let sub4: number = 1;
let sup4: any = sub4;
sub4 = sup4;
let sub5: never = 0 as never;
let sup5: number = sub5;
sub5 = sup5; // error Type 'number' is not assignable to type 'never'
class SubAnimal {}
class SubDog extends SubAnimal{
eat(){}
}
let sub6: SubDog = new SubDog();
let sup6: SubAnimal = sub6;
sub6 = sup6; // error Property 'eat' is missing type 'SubAnimal' but required in type 'SubDog'.
// 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 }> = sub9;
class Person {}
class Developer extends Person {
coding() {}
}
class StartupDeveloper extends Developer{
burning() {}
}
function tellme(f: (d: Developer)=> Developer) {}
// Developer 에다가 Developer 할당하는 경우
tellme(function dToD(d:Devleopr):Developer {
return new Developer();
});
// Developer 에다가 Person 할당하는 경우
tellme(function pToD(d:Person):Developer{
return new Developer();
});
// Developer 에다가 StartupDeveloper 할당하는 경우 (타입에러는 나지 않지만 기대하는 결과X)
tellme(function sToD(d:StartupDeveloper):Developer {
return new Developer();
});
strictFunctionTypes 옵션
함수의 매개변수 타입만 같거나 슈퍼타입의 경우가 아닌 경우, 에러를 통해 경고한다.
// 입력은 마음대로,
// 함수 구현은 문제 없도록
function funknown(a: unknown): number | string | void {
a.toString(); // error! Object is of type 'unknown'
// 명확하게 타입별로 처리하도록 유도
if(typeof a === 'number'){
return a * 38;
}else if(typeof a === 'string'){
return `Hello ${a}`;
}
}
let a = 'Mark'; // string
const b = 'Mark'; // 'Mark' => literal type
let c = 38; // number
const d = 38; // 38 => literal type
let e = false; // boolean
const f = false; // false => literal type
let g = ['Mark', 'Haeun']; // string[]
const h = ['Mark','Haeun']; // string[]
const f = ['Mark','Haeun'] as const; // readonly ['Mark','Haeun']
let j = [0,1,null]; // (number|null)[]
const k = [0,1,null]; // (number|null)[]
class Animal{}
class Rhino extends Animal{}
class Elephant extends Animal{}
class Snake extends Animal{}
let i = [new Rhino(),new Elephant(),new Snake()]; // (Rhino | Elephant|Snake)
const m = [new Rhino(),new Elephant(),new Snake()]; // (Rhino | Elephant|Snake)
const n = [new Animal(),new Rhino(),new Elephant(),new Snake()]; // Animal[]
const o: Animal[] = [new Rhino(),new Elephant(),new Snake()]; // Animal[]
// Parameter 'e' implicitly has an 'any' type.
const click = (e) => {
e; // any
};
document.addEventListener('click',click);
document.addEventListener('click',(e)=>{
e; // MouseEvent
});
function getNumber(value: number | string):number{
value; // number | string
if(typeof value === 'number'){
value; // number
return value;
}
value; // string
return -1;
}
interface IMachine {
name: string;
}
class Car implements IMachine {
name: string;
wheel: number;
}
class Boar implements IMachine {
name: string;
motor: number;
}
function getWhellOrMotor(machine: Car | Boat): number{
if(machine instanceof Car){
return machine.wheel; // Car
}else {
return machine.motor; // Boat
}
}
class NegativeNumberError extends Error {}
function getNumber(value: number): number | NegativeNumberError {
if(value < 0) return new NegativeNumberError();
return value;
}
function main(){
const num = getNumber(-10);
if(num instanceof NegativeNumberError){
return;
}
num; // number
}
interface Admin {
id: string;
role: string;
}
interface User {
id: string;
email: string;
}
function redirect(user: Admin | User) {
if("role" in user){
routeToAdminPage(user.role);
}else{
routeToHomePate(user.email);
}
}
interface IMachine {
type: string;
}
class Car implements IMachine {
type: 'CAR';
wheel: number;
}
class Boat implements IMachine {
type: 'BOAT';
motor: number;
}
function getWheelorMotor(machine: Car | Boat): number {
if(machine.type === 'CAR'){
return machine.wheel;
}else {
return machine.motor;
}
}
function getWheelOrMotor(machine:any):number{
if(isCar(machine)){
return machine.wheel;
}else if(isBoat(machine)){
return machine.motor;
}else{
return -1;
}
}
function isCar(arg:any):arg is Car {
return arg.type === 'CAR';
}
function isBoat(arg:any):arg is Boat {
return arg.type === 'BOAT';
}
class Square {
area: number;
sideLength: number;
}
const square = new Square();
console.log(square.area); // compile time - number, runtime - undefined
console.log(square.sideLength); // complie time - number, runtime - undefined
strictPropertyInitialization 옵션
class의 property 가 생성자 혹은 선언에서 값이 지정되지 않으면, 컴파일 에러를 발생시켜 주의를 준다.
class Square {
area: number = 0;
sideLength: number = 0;
}
class Square {
area: number;
sideLength: number;
constructor(sideLength: number){
this.sideLength = sideLength;
this.area = sideLength ** 2;
}
}
// 생성자에 의해 property 타입이 추론됨
class Square {
area;
sideLength;
constructor(sideLength: number){
this.sideLength = sideLength;
this.area = sideLength ** 2;
}
}
여전히 생성자를 벗어나면 추론되지 않는다
class Square {
sideLength!: number; // !로 의도를 표현해야 한다.
constructor(sideLength: number){
this.initialize(sideLength);
}
initialize(sideLength: number){
this.sideLength = sideLength;
}
get area(){
return this.sideLength ** 2;
}
}