DOM ์กฐ์์ด๋ ํจ์ ๋งค๊ฐ๋ณ์์์ null์ด๋ undefined ๊ฐ๋ฅ์ฑ ๋๋ฌธ์ ํ์
์๋ฌ๊ฐ ์์ฃผ ๋ฐ์ํ๋๋ฐ, ์ด๋ฅผ ์์ ํ๊ฒ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ๋ค์ ๋ฐฐ์๋ณด์!
๋จ์ธ = ์ฃผ์ ํ์ง ์๋ํ๊ณ ๋ฑ ์๋ผ ๋งํจ
as์ Non-null ๋จ์ธ ์ฐ์ฐ์: !// 1) DOM ์กฐ์์์์ ํ์
๋จ์ธ
const el = document.querySelector('body')
el.textContent = 'hello' // โ ์๋ฌ ๋ฐ์!
์ ์ฝ๋์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ์ด์ ๋ el์ด HTMLBodyElement | null ์ ๋์จ ํ์
์ผ๋ก ์ง์ ๋์ด ์๊ธฐ ๋๋ฌธ!
ํด๊ฒฐ ๋ฐฉ๋ฒ๋ค:
// ๋ฐฉ๋ฒ 1: as ํค์๋๋ก ์ง์ ํ์
๋จ์ธ
const el = document.querySelector('body') as HTMLBodyElement;
// ๋ฐฉ๋ฒ 2: Non-null ๋จ์ธ ์ฐ์ฐ์ ์ฌ์ฉ
el!.textContent = "hello"; // ๋๋ํ๋ "์ ๋ null์ด ์๋๋ค"๋ผ๊ณ ํ์
// ๋ฐฉ๋ฒ 3: ํ์
๊ฐ๋ ์ฌ์ฉ (๊ฐ์ฅ ์์ !)
if(el){
el.textContent = "hello";
}
// 2) ํจ์์์์ ํ์
๋จ์ธ
function getNumber(x: number | null | undefined){
return Number(x.toFixed(2)); // โ ์๋ฌ! toFixed๋ null/undefined ์ฒ๋ฆฌ ๋ถ๊ฐ
}
ํด๊ฒฐ ๋ฐฉ๋ฒ:
// ํ์
๋จ์ธ ์ฌ์ฉ
return Number((x as number).toFixed(2));
// ๋๋
return Number(x!.toFixed(2));
// ํ์ง๋ง getNumber(null) ํธ์ถ ์ TypeError ๋ฐ์! (์๋ชป๋ ํ์
๋จ์ธ)
// ํ์
๊ฐ๋๋ก ์์ ํ๊ฒ ์ฒ๋ฆฌ
if(x) { // undefined์ null์ ์กฐ๊ฑด๋ฌธ์์ ์ฐธ์ด ์๋๋ฏ๋ก ์์
return Number(x.toFixed(2));
}
// 3) ์กฐ๊ฑด๋ถ ํ์
๋จ์ธ
function getValue(x: string | number, isNumber: boolean){
if(isNumber){
return Number(x.toFixed(2)); // โ ์๋ฌ
}
return x.toUpperCase(); // โ ์๋ฌ
}
ํด๊ฒฐ:
if(isNumber){
return Number((x as number).toFixed(2));
}
return (x as string).toUpperCase();
// ์ฌ๊ธฐ์๋ null/undefined๊ฐ ์๋๋ฏ๋ก Non-null ์ฐ์ฐ์(!)๋ ๋ถํ์
let num: number;
console.log(num); // โ ํ์
์คํฌ๋ฆฝํธ ์๋ฌ (๊ฐ์ ํ ๋นํ์ง ์์)
// ์๋ฐ์คํฌ๋ฆฝํธ์์๋ undefined๋ก ์ถ๋ ฅ๋์ง๋ง TS์์๋ ์๋ฌ
ํด๊ฒฐ: ํ ๋น ๋จ์ธ ์ฌ์ฉ
let num!: number; // ํ ๋น ๋จ์ธ - "์ถํ ๊ฐ์ ํ ๋นํ ๊ฒ์ด๋ค"๋ผ๊ณ TS์๊ฒ ์๋ฆผ
console.log(num);
num = 123; // ๋์ค์ ํ ๋น
function logText(el: Element){
console.log(el.textContent);
}
const h1El = document.querySelector('h1');
logText(h1El); // โ ์๋ฌ! h1El์ด null์ผ ์ ์์
ํ์ ๋จ์ธ vs ํ์ ๊ฐ๋:
// ํ์
๋จ์ธ ์ฌ์ฉ (์ํ!)
const h1El = document.querySelector('h1') as HTMLHeadingElement;
// ์ฝ๋์ ์๋ฌ๋ ์์ง๋ง ์คํ ์ "Cannot read properties of null" ์๋ฌ ๋ฐ์ ๊ฐ๋ฅ
// ํ์
๊ฐ๋ ์ฌ์ฉ (์์ !)
if(h1El){
logText(h1El); // ์์ ํ๊ฒ ์ฌ์ฉ ๊ฐ๋ฅ
}
// ๋ ๊ตฌ์ฒด์ ์ธ ํ์
๊ฐ๋
if(h1El instanceof HTMLHeadingElement){
logText(h1El);
}
ํ์ค์นผ ์ผ์ด์ค๋ก ์์
interface User {
name: string;
readonly age: number; // ์ฝ๊ธฐ ์ ์ฉ ์์ฑ
isValid?: boolean; // ์ ํ์ ์์ฑ
}
const neo: User = {
name: 'sum',
age: 100,
isValid: true
};
neo.age = 200; // โ ์๋ฌ! readonly ์์ฑ์ ์์ ๋ถ๊ฐ
interface GetName {
(mes: string): string; // ์๊ดํธ๋ก ์์ฑํ๋ ๊ฒ์ด ํธ์ถ ์๊ทธ๋์ฒ
}
interface User {
name: string;
readonly age: number;
getName: GetName;
}
const user1: User = {
name: 'sum',
age: 100,
getName(mes: string) {
console.log(mes);
return this.name; // ํ์ดํ ํจ์๊ฐ ์๋๋ฏ๋ก ํธ์ถ ์ this ํ๋ณ ๊ฐ๋ฅ
}
};
user1.getName('coco'); // ์ ์ ์๋
ํจ์ ํ์ ์ ๋ฐ๋ก ๋ง๋๋ ์ด์ : ์ด๋ฆ์ ๊ฐ๊ณ ์ฌ์ฌ์ฉํ ์ ์๊ฒ ๋จ! ๋์ผํ ๊ตฌ์กฐ์ ํจ์๊ฐ ์๋ค๋ฉด ์ฌ์ฌ์ฉ ๊ฐ๋ฅ. ์ฌ์ฌ์ฉ์ฑ์ ๊ณ ๋ คํ์ฌ ํธ์ถ ์๊ทธ๋์ฒ๋ฅผ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ข์.
๋ฐฐ์ด๊ณผ ๊ฐ์ฒด์์ ๋๊ดํธ[]๋ก ๊ฐ์ธ์ ์ฌ์ฉํ๋ ๊ฒ
// ๋ฐฐ์ด ํ์
์ ์
interface Fruits {
[item: number]: string; // ์ธ๋ฑ์ค๋ number, ๊ฐ์ string
}
const fruits: Fruits = ['apple', 'banana', 'cherry'];
// ์ฝ์์ ์ฐ์ผ๋ฉด: 0: apple, 1: banana, 2: cherry
// ๊ฐ์ฒด ํ์
์ ์
interface User {
[key: string]: unknown; // ์ด๋ค ๊ฐ์ด ์ฌ์ง ๋ชจ๋ฅด๊ฒ ๋ค๊ณ ์ง์
name: string;
age: number;
}
const user1: User = {
name: 'sum',
age: 100
};
// ์ธ๋ฑ์ฑ์ผ๋ก ๊ฐ ์ถ๊ฐ ๊ฐ๋ฅ
user1['isValid'] = true;
user1['emails'] = ['sum529@naver.com', 'coyasium@gmail.com'];
interface UserA {
name: string;
age: number;
}
interface UserB extends UserA {
isValid: boolean;
}
const user2: UserB = {
name: 'sum',
age: 100,
isValid: true // UserA์ ์์ฑ + UserB์ ์์ฑ
};
์ธํฐํ์ด์ค ์ค๋ณต ์ ์ธ (Declaration Merging):
interface FullName {
firstName: string;
lastName: string;
}
interface FullName {
middleName: string;
// lastName: number; // โ ์๋ฌ! ๊ธฐ์กด ํ์
์ ๋ณ๊ฒฝ ๋ถ๊ฐ
}
// ๋ ์ธํฐํ์ด์ค๊ฐ ํฉ์ณ์ง!
// ์ ๋์จ ํ์
๊ฐ๋ฅ
type TypeA = string | number | boolean;
// ํํ ํ์
๊ฐ๋ฅ
type User1 = [string, number, boolean];
// ๋ณตํฉ ํ์
type User2 = {
name: string;
age: number;
isValid: boolean;
} | [string, number, boolean];
์ธํฐํ์ด์ค vs ํ์ ๋ณ์นญ:
interface Cat {
name: string;
age: number;
}
const cat: Cat = {
name: 'sum',
age: 10
};
function fi(mes: string){
console.log(`${this.name}, ${mes}`); // โ this์์ ์๋ฌ
}
fi.call(cat, 'meow'); // call ๋ฉ์๋๋ก cat ๊ฐ์ฒด์ ๋ฉ์๋์ฒ๋ผ ํธ์ถ
์๋ฌ ์์ธ: this์๋ ํ์ ์ฃผ์์ด ์์ผ๋ฏ๋ก ์์์ ์ผ๋ก any ํ์ ํฌํจ (TS์ ์๊ฒฉํ ๋ฌธ๋ฒ ๊ฒ์ฌ)
ํด๊ฒฐ:
function fi(this: Cat, mes: string){ // this ํ์
๋ช
์ (๋งค๊ฐ๋ณ์๊ฐ ์๋ TS ๋ฌธ๋ฒ)
console.log(`${this.name}, ${mes}`);
}
๊ธฐ์กด ๋นํจ์จ์ ์ธ ์ฝ๋:
function add1(a: string, b: string) {
return a + b;
}
function add2(a: number, b: number) {
return a + b;
}
// ๋ถํ์ํ ์ค๋ณต ์ฝ๋!
์ค๋ฒ๋ก๋ฉ ์ฌ์ฉ:
function add(a: string, b: string): string; // ํ์
์ ์ธ
function add(a: number, b: number): number; // ํ์
์ ์ธ
function add(a: any, b: any) { // ํจ์ ๊ตฌํ
return a + b;
}
add('h', 'i'); // ์ ์
add(2, 3); // ์ ์
add('h', 1); // โ ์๋ฌ
์ค๋ฒ๋ก๋ฉ์ด๋? ํ๋์ ํจ์ ์ด๋ฆ์ ์ฌ๋ฌ ํ์
์ ๋งค๊ฐ๋ณ์ ์๊ทธ๋์ฒ๋ฅผ ์ ์ธํด ๋ค์ํ ์
๋ ฅ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ๋์ํ๋๋ก ๋ง๋๋ ๊ธฐ๋ฅ. ์ฌ๊ธฐ์ any๋ ์ค์ ํ์
์ด ์๋๋ผ "ํ์
์ ์ธํ ๋ฐฉ์ ์ค ์ด๋ค ๊ฒ์ด๋ ํ ๋น๋ ์ ์๋ค"๋ ์๋ฏธ.
ํจ์ ์ ๋ค๋ฆญ:
// ์ค๋ฒ๋ก๋ฉ ๋์ ์ ๋ค๋ฆญ ์ฌ์ฉ
function add<T>(a: T, b: T) {
return a + b;
}
์ธํฐํ์ด์ค ์ ๋ค๋ฆญ๊ณผ ์ ์ฝ ์กฐ๊ฑด:
// ๊ธฐ๋ณธ ์ ๋ค๋ฆญ ์ธํฐํ์ด์ค
interface MyData<T> {
name: string;
value: T;
}
const dataA: MyData<string> = {
name: 'data',
value: 'hello'
};
const dataB: MyData<number[]> = {
name: 'data',
value: [1, 2]
};
// ์ ์ฝ ์กฐ๊ฑด์ด ์๋ ์ ๋ค๋ฆญ
interface MyData<T extends string | number> {
name: string;
value: T;
}
const dataC: MyData<number[]> = { // โ ์๋ฌ! number[]๋ ์ ์ฝ ์กฐ๊ฑด์ ๋ง์ง ์์
name: 'data',
value: [1, 2]
};
import _ from 'lodash';
const str = 'xxxx xxx xxx';
console.log(_.camelCase(str));
console.log(_.snakeCase(str));
ํ์ ์ ์ธ ํ์ผ ์์ฑ (ํจํค์ง๋ช .d.ts):
declare module 'lodash' {
interface Lodash {
camelCase: (str: string) => string;
snakeCase: (str: string) => string;
}
const _: Lodash;
export default _;
}
์ผ์ค ์ฌ๋์ ์ง์์ (Triple-slash directive):
/// <reference path="./main.d.ts"/>
๋ ํธํ ๋ฐฉ๋ฒ:
# ํ์
์กด์ฌ ํ์ธ
$ npm info @types/lodash
# ๊ฐ๋ฐ ์์กด์ฑ์ผ๋ก ํ์
์ค์น
$ npm i @types/lodash -D
// โ ์ํํ ๋ฐฉ๋ฒ
const button = document.querySelector('button');
button.addEventListener('click', () => {}); // ์๋ฌ ๋ฐ์ ๊ฐ๋ฅ
// โ
ํ์
๊ฐ๋ ์ฌ์ฉ
const button = document.querySelector('button');
if (button) {
button.addEventListener('click', () => {});
}
// โ
ํ์
๋จ์ธ ์ฌ์ฉ (ํ์คํ ๋๋ง!)
const button = document.querySelector('button') as HTMLButtonElement;
button.addEventListener('click', () => {});
extends ํค์๋๋ก ์ ๋ค๋ฆญ ํ์
์ ํน์ ์กฐ๊ฑด์ผ๋ก ์ ํ ๊ฐ๋ฅ