Use JavaScript more strictly (feat. TypeScript, flow)Mark Lee
[DevFest Seoul 2018] JavaScript 에 Type System 을 도입하는 대표적인 방법인 Flow 와 TypeScript 를 알아본다. TypeScript 의 strict 모드를 이용해서 좀 더 견고한 JavaScript 어플리케이션을 만드는 방법에 대해 공유한다.
Use JavaScript more strictly (feat. TypeScript, flow)Mark Lee
[DevFest Seoul 2018] JavaScript 에 Type System 을 도입하는 대표적인 방법인 Flow 와 TypeScript 를 알아본다. TypeScript 의 strict 모드를 이용해서 좀 더 견고한 JavaScript 어플리케이션을 만드는 방법에 대해 공유한다.
여러 언어에서 null 안전성을 주요 마케팅 쟁점으로 내세우면서 null 안전성이 관심을 많이 받고 있습니다.
자바에서도 null을 잘 다루어야 소프트웨어 결함을 줄이고 견고하게 만들 수 있는데 null의 위협에서 코드를 안전하게 지키는 설계 지침을 정리하고 안전하다고 확인하는데 도움이 되는 도구를 소개합니다.
6. Duck Typing
덕타이핑(Duck Typing)이라고 많이들어보셨을텐데요, 현재이덕타이핑
체계를기반으로동적언어에타입을추론하는언어는GoLang과 Python 등
이있습니다. 하지만TypeScript는이덕타이핑과는조금 다른체계로
Typing을하고 있습니다.
덕타이핑에대한보다자세한내용은여기를참고해주세요.
7. Structural typing
TypeScript는Structural typing (구조적타이핑)을기반으로타입시스템
을갖추고 있습니다. 구조적타이핑이란, 멤버 에따라타입을연관짓는방법
을말합니다. 구조적타이핑과 반대인방법으로 nominal typing 이있습니
다. 우리가 알고 있는일반적인정적언어인C#, Java는이 nominal
typing 방식으로type checking이이루어집니다.
8. _Official Document_에나온예제를통해설명드립니다.
interface Named {
name: string;
}
class Person {
name: string;
}
let p: Named;
p = new Person(); // Ok, because of structural typing
위코드를C# 또는Java의문법에맞게 변경한다면동작하지않는잘못된코
드가 됩니다. 하지만TypeScript에서는정상적으로동작합니다. Named 와
Person 두가지는오로지 name 이라는프로퍼티(or 멤버)만갖고 있는타
입이므로서로 compatibility 하다고 볼수있습니다. 때문에위코드는문
제되지않습니다. (compatibility에대해서는뒤에서알아봅니다.)
15. const initialState: Todos = [
{
id: 0,
text: 'Study RxJS',
completed: false,
} as Todo
];
위코드처럼 as 키워드를사용할수있습니다. 두가지모두동일하지만
tsx 와함께사용하기 위해서는 as 키워드를사용하는것이좋습니다.
19. typeof , instanceof
TypeScript에서도마찬가지로 typeof 와 instanceof 오퍼레이터를지
원합니다.
function setNumberOrString(x: number | string) {
if (typeof x === 'string') {
console.log(x.subtr(1)); // Error
console.log(x.substr(1)); // OK
} else {
console.log(typof x); // number
}
x.substr(1); // Error
}
위코드에서 if-block 내에서의 x 변수의타입은 string 일수밖에없다
는것을컴파일시점에체크하여transpiler가 Error를발생시키는경우입니다.
이예제와비슷한방법으로 instanceof 오퍼레이터를사용할수있습니다.
instanceof 는클래스를기반으로생성된인스턴스의타입을판단하는데
사용됩니다.
20. class Pet {
name = 123;
common = '123';
}
class Basket {
size = 123;
common = '123';
}
21. function create(arg: Pet | Basket) {
if (arg instanceof Pet) {
console.log(arg.name); // OK
console.log(arg.size); // Error!
}
if (arg instanceof Basket) {
console.log(arg.name); // Error!
console.log(arg.size); // OK
}
console.log(arg.common); // OK
console.log(arg.name); // Error!
console.log(arg.size); // Error!
}
typeof 와마찬가지로 instanceof 로필터링된block 내부에서Type
checking이이루어집니다.
22. in
interface A {
x: number;
}
interface B {
y: string;
}
function execute(q: A | B) {
if ('x' in q) {
// q: A
} else {
// q: B
}
}
A 또는 B 를유니온타입으로받을수있는 execute 함수내에서각각에
대해다른처리를할경우, in 이라는오퍼레이터를사용할수있습니다. 해당
오퍼레이터는check하고자하는타입에해당프로퍼티가 존재하는지의유무
를판단할수있습니다.
24. type Foo = {
kind: 'foo', // Literal type
foo: number
}
type Bar = {
kind: 'bar', // Literal type
bar: number
}
function execute(arg: Foo | Bar) {
if (arg.kind === 'foo') {
console.log(arg.foo); // OK
console.log(arg.bar); // Error!
}
}
위코드에서처럼 type 키워드를사용하여별도타입을지정할때, kind 라
는프로퍼티를추가하여타입검사를수행할수있습니다.
25. User Defined Type Guards
메소드를별도로분리하여Type Guard를지정할수있습니다. 아까 지정한
interface A로만들어보겠습니다.
interface A {
x: number;
}
// Define Type Guard
function isA(arg: any): arg is A {
return arg.x !== undefined;
}
arg is A 라는타입으로 isA 메소드가 Type Guard의역할을수행한다
는것을명시할수있습니다. if 내부에들어가는로직을별도로추출하여보다
가독서이좋은코드를작성할수있습니다.
27. 1. Comparing two Objects
let x = {name: `Jbee`};
let y = {name: `James`, age: 34};
x = y; // OK!
y = x; // Error!
위코드에서 x 는 {name: string} 타입으로추론되며, y 는 {name:
string, age: number} 로추론됩니다. 이경우 x = y 는 y 에 name 이
라는속성이있으므로가능하지만 y = x 의경우, x 에는 age 라는속성이
없으므로에러가 발생합니다.
28. 2. Comparing two functions
let x = (a: number) => 0;
let y = (b: number, s: string) => 0;
y = x; // OK
x = y; // Error
함수일경우에는객체인경우와조금 다른것을볼수있습니다. 위코드에서
두 x , y 함수는parameter 만다르게 정의되어있습니다. 이경우, x 함수
에전달할수있는parameter의경우의수가 y에모두해당하므로 y = x 가
정상적으로동작합니다. 하지만그 반대인 x = y 는 y 함수에전달할수있
는parameter를 x 가 모두포용할수없으므로에러가 발생합니다.
29. let x = () => ({name: `Jbee`});
let y = () => ({name: `James`, age: 34});
x = y; // OK!
y = x; // Error!
이번에는return value의type이다른경우입니다. 이경우에는함수의경우
를따르지않고 객체인경우를따르게 됩니다.
31. Reference
TypeScript Official Document ‑ Type Inference
TypeScript Official Document ‑ Type Compatibility
Golang으로만나보는duck typing
Type Systems: Structural vs Nominal typing explained
TypeScript Deep dive ‑ Type Guard