const names = ['Alice', 'Bob'];
console.log(names[2].toUpperCase());
tsconfig.json
파일로도 가능하다noImplicitAny
와 strickNullChecks
noImplicitAny
: 변수들이 미리 정의된 타입을 가져야 하는지 여부 제어strickNullChecks
: null
과 undefined
가 모든타입에서 허용 되는지 확인하는 설정타입 스크립트 컴파일러는 두가지 역할을 독립적으로 수행
독립적으로 수행되기때문에 타입오류가 있는 코드도 컴파일이 가능하다
interface Square {
width: number;
}
interface Rectangle extends Square {
height: number;
}
type Shape = Square | Rectangle;
function calculateArea(shape: Shape) {
if (shape instanceof Rectangle) {
// 'Rectangle' only refers to a type,
// but is being used as a value here
return shape.width * shape.height;
// Property 'height' does not exist
// on type 'Shape'
} else {
return shape.width * shape.width;
}
}
interface
,type
은 제거된다.그래서 명확하게 하기 위해서는 아래 코드와 같이 런타임에 타입 정보를 유지하는 방법이 필요합니다 .
1. 속성 체크
interface Square {
width: number;
}
interface Rectangle extends Square {
height: number;
}
type Shape = Square | Rectangle;
function calculateArea(shape: Shape) {
if ('height' in shape) {
shape; // Type is Rectangle
return shape.width * shape.height;
} else {
shape; // Type is Square
return shape.width * shape.width;
}
}
interface Square {
kind: 'square';
width: number;
}
interface Rectangle {
kind: 'rectangle';
height: number;
width: number;
}
type Shape = Square | Rectangle;
function calculateArea(shape: Shape) {
if (shape.kind === 'rectangle') {
shape; // Type is Rectangle
return shape.width * shape.height;
} else {
shape; // Type is Square
return shape.width * shape.width;
}
}
class Square {
constructor(public width: number) {}
}
class Rectangle extends Square {
constructor(public width: number, public height: number) {
super(width);
}
}
type Shape = Square | Rectangle; // 타입으로 참조
function calculateArea(shape: Shape) {
if (shape instanceof Rectangle) { // shape instanceof Rectangle 값으로 참조
shape; // Type is Rectangle
return shape.width * shape.height;
} else {
shape; // Type is Square
return shape.width * shape.width; // OK
}
}
interface LightApiResponse {
lightSwitchValue : boolean;
}
async function setLight(){
const response = await fetch('/light');
const result : LightApiResponse = await response.json();
setLightSwitch(result.lightSwitchValue);
}
function setLightSwitch(value: boolean) {
switch (value) {
case true:
turnLightOn();
break;
case false:
turnLightOff();
break;
default:
console.log(`I'm afraid I can't do that.`);
}
}
lightSwitchValue
의 값이 boolean
이 아니라 문자열
이라면 default가
발생하게 됩니다.Typescript
에서는 런타임타입과 선언된타입이 맞지 않을 수 있습니다.function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a, b) {
return a + b;
}
interface Vector2D {
x: number;
y: number;
}
function calculateLength(v: Vector2D) {
return Math.sqrt(v.x * v.x + v.y * v.y);
}
interface NamedVector {
name: string;
x: number;
y: number;
}
const v: NamedVector = { x: 3, y: 4, name: 'Zee' };
calculateLength(v); // OK, result is 5
//NamedVector를 위한 calculateLength를 구현할 필요가 없음
interface Vector2D {
x: number;
y: number;
}
function calculateLength(v: Vector2D) {
return Math.sqrt(v.x * v.x + v.y * v.y);
}
interface NamedVector {
name: string;
x: number;
y: number;
}
interface Vector3D {
x: number;
y: number;
z: number;
}
function calculateLengthL1(v: Vector3D) {
let length = 0;
for (const axis of Object.keys(v)) {
const coord = v[axis];
// 타입 호환때문에 v[axis]의 타입은 어떤 속성이 될 지 모르기때문에 number라고 확정지을 수 없음
// 따라서 coord는 any type
length += Math.abs(coord);
}
return length;
}
const vec3D = {x: 3, y: 4, z: 1, address: '123 Broadway'};
calculateLengthL1(vec3D); // OK, returns NaN
테스트를 작성할때는 구조적 타이핑이 유리합니다
interface Author {
first: string;
last: string;
}
interface DB {
runQuery: (sql: string) => any[];
}
function getAuthors(database: DB): Author[] {
const authorRows = database.runQuery(`SELECT FIRST, LAST FROM AUTHORS`);
return authorRows.map(row => ({first: row[0], last: row[1]}));
}
any
는 타입 안정성이 떨어진다.any
는 함수 시그니처를 무시해 버린다.any
타입은 언어 서비스가 적용되지 않는다.아래와 같이 자동완성으로 속성이 나타나지 않는다.
any
타입은 코드 리팩터링때 버그를 감춥니다.interface ComponentProps {
onSelectItem: (item: any) => void;
}
function renderSelector(props: ComponentProps) { /* ... */ }
let selectedId: number = 0;
function handleSelectItem(item: any) {
selectedId = item.id;
}
renderSelector({onSelectItem: handleSelectItem});
handleSelectItem
의 매개변수 item이 any
로 설정했기때문에 id의 유무에 상관없이 문제가 없다고 할것입니다.
하지만 id의 값이 존재하지 않는다면 타입체커를 통과함에도 불구하고 런타임에는 오류가 발생할 것입니다.
만약 any
가 아닌 구체적인 타입을 사용했다면, 타입체커가 오류를 발견했을 것입니다.
요즘은 왜 글이 안 올라오나여?