타입을 따로 지정하지 않아도, 에디터 상에서 해당 변수에 타입이 지정되는 방식이다. 기본적인 선언과 할당에 대해서 진행되어 진다.
let a = 10; //type number
function getB(b = 10){
let c = 'hi';
return b + c;
}
let b = getB();// type string
interface Dropdown<T> {
value : T;
title : string;
}
let shoppingItem:Dropdown<string> = {
value: 'abc',
title: 'hello'
}
제네릭을 통해서 value값이 string을 가진다는 것을 에디터가 추론함
interface Dropdown<T> {
value : T;
title : string;
}
//K라고 주는 것은 제네릭을 구별하기 위해서 쓴 것이고 관행적으로는 T를 사용함
interface DetailedDropdown<K> extends Dropdown<K>{
description : string;
tag: K;
}
let detaildItem: DetailedDropdown<string> = {
title: 'abc',
description: 'aabbcc',
value: 'string type',
tag: 'string type'
}
인터페이스 확장을 통해서 타입이 지정된 것도 타입추론에 의해 에디터가 추론함
일반적으로 타입스크립트보다 개발자가 타입에 대해서 더 잘알고 있기 때문에 타입을 개발자가 정의한 타입으로 선언하는 것을 타입 단언이라 한다. Dom API 조작시 가장 많이 사용되어 진다.
let a;
a = 20;
a = 'a';
let b = a as string; //타입 단언
// DOM API 조작
//일반적인 방법
const div = document.querySelector('div'); //타입 HTMLDivElement || Null
//div가 언제나 HTMLDivElement가 아니기 때문에 if문으로 null이 아님을 보장해줘야 한다.
if(div){
div.innerText
}
//타입단언(as)
const div = document.querySelector('div') as HTMLDivElement; // 타입이 Null이 아님을 타입단언으로 개발자가 보장하는 방식
div.innerText
interface Developer {
name : string;
skill: string;
}
interface Person{
name : string;
age : number;
}
function introduce(): Developer | Person{
return { name : 'Tony', age: 33, skill: "Iron Making"}
}
let tony = introduce();
console.log(tony.skill) //error, 유니온타입일 경우 공통된 속성만 접근 가능하기 때문에
// 타입단언 방식의 문제점: 가독성 문제
if((tony as Developer).skill){
let skill = (tony as Developer).skill;
console.log(skill);
}
// 타입가드 방식(is)
function isDeveloper(target: Developer | Person): target is Developer {
return (target as Developer).skill !== undefined;
}
if(isDeveloper(tony)) {
tony.skill //접근가능
}else {
tony.age //접근가능
}
target is Developer는 target을 Developer 타입으로 선언하겠다는 말이다. 즉, target값이 들어왔을 때 그 값이 skill값을 가지고 있다면 target에 대한 타입을 Developter로 정의하는 것을 말한다.
타입스크립트 코드에서 특정 타입이 다른 타입에 잘 맞는지를 확인하는 것을 의미한다.
interface Developer {
name: string;
skill: string;
}
interface Person{
name: string;
}
let developer: Developer;
let person: Person;
developer = person; // error, 두 변수의 구조가 다르기 때문에 에러가 난다.
person = developer; // error X, developer의 구조가 더 크기 때문에 에러가 없다.
developer = new Person(); // error
타입호환은 = 을 기준으로 오른쪽의 구조가 왼쪽의 구조보다 클 경우에 호환이 된다고 한다. 꼭 인터페이스가 아니더라도 클래스, 함수, 제네릭 같은 곳에서도 동일하게 적용된다.
const add = function(a: number){
...
}
const sum = function(a: number, b: number){
...
}
add = sum; //error
sum = add; //error X
interface Empty<T>{
...
}
interface NotEmpty<T>{
data: T;
}
let empty1: Empty<string>;
let empty2: Empty<number>;
empty1 = empty2; //error X
empty1 = empty2; //error X
let notEmpty1: NotEmpty<string>;
let notEmpty2: NotEmpty<number>;
// 인터페이스 안에 타입이 서로 다르기 때문에 에러
notEmpty1 = notEmpty2 // error
notEmpty2 = notEmpty1 // error