parameter에 대한 type annotation이 되어 있지 않더라도 TypeScript에서 파라미터 갯수는 체크함
return 문 기반으로 함수의 반환 타입을 알아서 추론해줌
Return type 붙이는건 documentation, 혹은 명시적으로 표기하기 위함임
익명 함수
익명 함수가 TypeScript가 어떻게 호출되는지를 결정할 수 있는 곳에서 정의된다면, 해당 함수의 파라미터는 자동으로 타입이 주어짐
오브젝트 타입
Optional Properties
object type에서 property가 optional이라는 것을 명시하기 위해서는 ? 를 property name에 붙이면 됨
JavaScript에서는 존재하지 않는 값에 접근하면 Runtime error가 아닌 undefined 값을 얻기 때문에 그 값을 이용하기 위해서는 그 전에 check 하는 과정이 필요함
? 연산자를 이용하여 값이 있을때에만 작동하게 작성 가능함
Union Type
값이 여러 타입 중 하나 임을 명시하고 싶을 때 Union Type을 사용함
Union Type들의 모든 타입에 대해서 가능한 로직을 함수 내부에 작성해야함
Type Aliases
Type 선언을 계속해서 재활용하고 싶을 때 type에 name을 붙여서 활용하게 하는 것임
type에 name을부여하고 싶을 때 사용
Interfaces
object type에 이름을 붙일 수 있는 또다른 방법
Type Aliases 🆚 Interfaces
둘은 되게 비슷해서 둘 중에 자유롭게 선택해서 사용하면 됨
두 개 사이의 뚜렷한 차이는 type은 새 property를 추가하기 위해 새롭게 정의될 수 없는데 interface는 그것이 언제나 가능함
Type Assertion
TypeScript 가 모르는 정보를 우리가 더 알고 있을 수도 있음
예를 들어 document.getElementById 에서 반환되는 타입이 TypeScript 는 HTMLElement 의 종류 라고만 알고 있는데, 내가 짠 코드에서는 HTMLCanvasElement 만 반환한다는 것을 알고 있을 때, Type Assertion을 쓸 수 있음
TypeScript는 type을 조금 더 상세한 또는 조금 덜 상세한 타입으로 바꾸는 것만 허용함. 예를 들어 string 을 number로 바꾸는 건 에러를 띄움
Literal Types
type이 구체적인 string과 number 를 가리키도록 할 수 있음
const로 선언한 constantString의 타입은 “Hello World” 임 string이 아니라
사용예시 — 허용 가능한 값을 명시하는 용도로 사용가능함
null and undefined
Non-null Assertion Operator (Postfix !)
변수 뒤에 ! 를 붙이면 해당 변수는 null이나 undefined 가 아니라고 명시적으로 말해주는 것임
In addition to creating an object with property names for members, numeric enums members also get a reverse mapping from enum values to enum names. For example, in this example:
iterate
let myname: string = "Alice";
// No type annotation needed -- 'myName' inferred as type 'string'
let myName = "Alice";
function getFavoriteNumber(): number {
return 26;
}
Return Type Annotation
// No type annotations here, but TypeScript can spot the bug
const names = ["Alice", "Bob", "Eve"];
// Contextual typing for function
names.forEach(function (s) {
console.log(s.toUppercase());
Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
});
// The parameter's type annotation is an object type
function printCoord(pt: { x: number; y: number }) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });
function printName(obj: { first: string; last?: string }) {
// ...
}
// Both OK
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });
function printName(obj: { first: string; last?: string }) {
// Error - might crash if 'obj.last' wasn't provided!
console.log(obj.last.toUpperCase());
Object is possibly 'undefined'.
if (obj.last !== undefined) {
// OK
console.log(obj.last.toUpperCase());
}
// A safe alternative using modern JavaScript syntax:
console.log(obj.last?.toUpperCase());
}
function printId(id: number | string) {
console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// Error
printId({ myID: 22342 });
Argument of type '{ myID: number; }' is not assignable to parameter of type 'string | number'.
type Point = {
x: number;
y: number;
};
// Exactly the same as the earlier example
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
type ID = number | string;
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
// Extending a type via intersections
type Animal = {
name: string
}
type Bear = Animal & {
honey: boolean
}
const bear = getBear();
bear.name;
bear.honey;
// A type cannot be changed
// after being created
type Window = {
title: string
}
type Window = {
ts: TypeScriptAPI
}
// Error: Duplicate identifier 'W
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
Type assertion to specify a more specific type
const x = "hello" as number;
Conversion of type 'string' to type 'number' may be a mistake because
neither type sufficiently overlaps with the other.
If this was intentional, convert the expression to 'unknown' first.
let changingString = "Hello World";
changingString = "Olá Mundo";
// Because `changingString` can represent any possible string, that
// is how TypeScript describes it in the type system
changingString;
/* let changingString: string */
const constantString = "Hello World";
// Because `constantString` can only represent 1 possible string, it
// has a literal type representation
constantString;
/* const constantString: "Hello World" */
let x: "hello" = "hello";
// OK
x = "hello";
// ...
x = "howdy";
Type '"howdy"' is not assignable to type '"hello"'.
literal type은 그것 자체로는 크게 가치가 없음
function printText(s: string, alignment: "left" | "right" | "center") {
// ...
}
printText("Hello, world", "left");
printText("G'day, mate", "centre");
Argument of type '"centre"' is not assignable to parameter of type '"left" | "right" | "center"'.
literal을 union으로 묶어서 이용할 때, 조금 더 유용하게 이용할 수 있음. 받을 수 있는 값을 명시하는 용도로.
function compare(a: string, b: string): -1 | 0 | 1 {
return a === b ? 0 : a > b ? 1 : -1;
}
numeric literal types도 똑같이 동작함
enum Enum {
A,
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
Try