TypeScriptμ νμ
μ²΄ν¬ μ΅μ
μ μ½λμ μμ μ±μ κ²°μ ν©λλ€. Sonamuλ strict λͺ¨λλ₯Ό κΈ°λ³ΈμΌλ‘ νμ±ν νμ¬ μ΅λνμ νμ
μμ μ±μ μ 곡ν©λλ€.
Strict λͺ¨λ
Sonamuλ λͺ¨λ strict μ΅μ
μ νμ±νν©λλ€.
{
"compilerOptions" : {
"strict" : true , // λͺ¨λ strict μ΅μ
νμ±ν
"noImplicitAny" : true , // any νμ
λͺ
μ νμ
"strictNullChecks" : true , // null/undefined μ격 체ν¬
"strictFunctionTypes" : true , // ν¨μ νμ
μ격 체ν¬
"strictBindCallApply" : true , // bind/call/apply μ격 체ν¬
"strictPropertyInitialization" : true , // ν΄λμ€ νλ‘νΌν° μ΄κΈ°ν νμ
"noImplicitThis" : true , // this νμ
λͺ
μ νμ
"alwaysStrict" : true // 'use strict' μλ μΆκ°
}
}
strict: trueλ μμ λͺ¨λ μ΅μ
μ ν λ²μ νμ±ννλ λ¨μΆ μ€μ μ
λλ€.
Strict μ΅μ
μμΈ
any νμ
λͺ
μ νμ κΈ°λ₯:
νμ
μ μΆλ‘ ν μ μμ λ anyλ₯Ό μ묡μ μΌλ‘ μ¬μ©νμ§ λͺ»νλλ‘ λ°©μ§
μμ: // β μλ¬ λ°μ
function log ( message ) {
// ^^^^^^^ Parameter 'message' implicitly has an 'any' type
console . log ( message );
}
// β
μ¬λ°λ₯Έ μ½λ
function log ( message : string ) {
console . log ( message );
}
// β
μ λ€λ¦ μ¬μ©
function log < T >( message : T ) {
console . log ( message );
}
νμ
μ λͺ
μνκΈ° μ΄λ €μ΄ κ²½μ° unknownμ μ¬μ©νμΈμ. anyλ³΄λ€ μμ ν©λλ€.
null/undefined μ격 μ²΄ν¬ κΈ°λ₯:
nullκ³Ό undefinedλ₯Ό λ€λ₯Έ νμ
μ ν λΉν μ μλλ‘ λ°©μ§
λͺ¨λ νμ
μ΄ κΈ°λ³Έμ μΌλ‘ non-nullable
μμ: // β μλ¬ λ°μ
let name : string = null ;
// ^^^^ Type 'null' is not assignable to type 'string'
// β
Union νμ
μ¬μ©
let name : string | null = null ;
name = "Alice" ;
// β
Optional 체μ΄λ
interface User {
email ?: string ;
}
function sendEmail ( user : User ) {
// β μλ¬ λ°μ
const length = user . email . length ;
// ^^^^^ Object is possibly 'undefined'
// β
Optional 체μ΄λ
const length = user . email ?. length ;
// β
null 체ν¬
if ( user . email !== undefined ) {
const length = user . email . length ;
}
}
Sonamuμμ: // entity.jsonμΌλ‘ μ μλ Entity μ¬μ©
interface User {
id : number ;
name : string ; // nullμ΄ λ μ μμ
bio : string | null ; // null νμ©
email ?: string ; // undefined νμ©
created_at : Date ;
}
// Model ν΄λμ€μμ νμ
μμ μ± ν보
class UserModelClass extends BaseModelClass {
@ api ({ httpMethod: "GET" })
async findById (
subset : UserSubsetKey ,
id : number
) : Promise < UserSubsetMapping [ typeof subset ] | null > {
const rdb = this . getPuri ( "r" );
const user = await rdb . table ( "users" ). where ( "id" , id ). first ();
// strictNullChecksκ° null 체ν¬λ₯Ό κ°μ ν¨
if ( ! user ) {
return null ;
}
return user ;
}
}
ν¨μ νμ
μ격 μ²΄ν¬ κΈ°λ₯:
ν¨μ νλΌλ―Έν°μ contravariance(λ°κ³΅λ³μ±) 체ν¬
λ μμ ν ν¨μ νμ
νΈνμ±
μμ: interface Animal {
name : string ;
}
interface Dog extends Animal {
bark () : void ;
}
// β μλ¬ λ°μ (strictFunctionTypes: true)
let animalHandler : ( animal : Animal ) => void ;
let dogHandler : ( dog : Dog ) => void ;
animalHandler = dogHandler ;
// ^^^^^^^^^ Type '(dog: Dog) => void' is not assignable to type '(animal: Animal) => void'
// β
μ¬λ°λ₯Έ λ°©ν₯
dogHandler = animalHandler ; // OK
μ΄ μ΅μ
μ ν¨μμ νμ
μμ μ±μ ν¬κ² ν₯μμν€μ§λ§, μΌλΆ λΌμ΄λΈλ¬λ¦¬μ νΈνμ± λ¬Έμ κ° μμ μ μμ΅λλ€.
bind/call/apply μ격 μ²΄ν¬ κΈ°λ₯:
bind, call, apply λ©μλμ νλΌλ―Έν° νμ
체ν¬
μμ: function greet ( name : string , age : number ) {
console . log ( `Hello, ${ name } ! You are ${ age } years old.` );
}
// β μλ¬ λ°μ
greet . call ( null , "Alice" , "30" );
// ^^^^ Argument of type 'string' is not assignable to parameter of type 'number'
// β
μ¬λ°λ₯Έ νμ
greet . call ( null , "Alice" , 30 );
// β μλ¬ λ°μ
greet . apply ( null , [ "Alice" ]);
// ^^^^^^^^^ Argument of type '[string]' is not assignable to parameter of type '[string, number]'
// β
μ¬λ°λ₯Έ μΈμ μ
greet . apply ( null , [ "Alice" , 30 ]);
ν΄λμ€ νλ‘νΌν° μ΄κΈ°ν νμ κΈ°λ₯:
ν΄λμ€ νλ‘νΌν°κ° μμ±μμμ μ΄κΈ°νλμλμ§ νμΈ
μμ: class User {
// β μλ¬ λ°μ
name : string ;
// ^^^^ Property 'name' has no initializer and is not definitely assigned in the constructor
// β
μμ±μμμ μ΄κΈ°ν
email : string ;
constructor ( email : string ) {
this . email = email ;
}
// β
κΈ°λ³Έκ° μ 곡
age : number = 0 ;
// β
Optional
bio ?: string ;
// β
null νμ©
avatar : string | null = null ;
// β
Definite assignment assertion (νμ€ν κ²½μ°λ§)
id !: number ;
}
Sonamuμμ: // Generated νμ
μ λͺ¨λ μ΄κΈ°νλ¨
interface UserRow {
id : number ; // DBμμ μλ μμ±
email : string ; // νμ νλ
name : string ; // κΈ°λ³Έκ° "guest"
created_at : Date ; // κΈ°λ³Έκ° CURRENT_TIMESTAMP
}
// Model ν΄λμ€μμ Definite Assignment Assertion μ¬μ©
class UserModelClass extends BaseModelClass {
// μμ±μμμ μ΄κΈ°νλλ―λ‘ !
private readonly tableName !: string ;
constructor () {
super ();
this . tableName = "users" ;
}
@ api ({ httpMethod: "POST" })
async create ( data : UserSaveParams ) {
// dataλ λ°λμ νμ νλλ₯Ό ν¬ν¨ν΄μΌ ν¨
const wdb = this . getDB ( "w" );
return this . insert ( wdb , data );
}
}
this νμ
λͺ
μ νμ κΈ°λ₯:
thisμ νμ
μ΄ λͺ
ννμ§ μμ λ μλ¬ λ°μ
μμ: // β μλ¬ λ°μ
function onClick () {
console . log ( this . textContent );
// ^^^^ 'this' implicitly has type 'any'
}
// β
this νμ
λͺ
μ
function onClick ( this : HTMLElement ) {
console . log ( this . textContent );
}
// β
νμ΄ν ν¨μ (this λ°μΈλ© μμ)
const onClick = () => {
// μΈλΆ this μ¬μ©
};
// β
ν΄λμ€ λ©μλ
class Button {
text : string = "Click me" ;
onClick () {
console . log ( this . text ); // OK
}
}
μΆκ° νμ
μ²΄ν¬ μ΅μ
Sonamuλ strict λͺ¨λ μΈμλ μΆκ° μ²΄ν¬ μ΅μ
μ νμ±νν©λλ€.
{
"compilerOptions" : {
"noUnusedLocals" : true ,
"noUnusedParameters" : true ,
"noImplicitReturns" : true ,
"noFallthroughCasesInSwitch" : true ,
"useUnknownInCatchVariables" : true ,
"noUncheckedIndexedAccess" : true
}
}
Unused 체ν¬
Return 체ν¬
Switch 체ν¬
Catch λ³μ
μΈλ±μ€ μ κ·Ό
μ¬μ©νμ§ μλ μ½λ κ²½κ³ {
"noUnusedLocals" : true ,
"noUnusedParameters" : true
}
μμ: // β noUnusedLocals μλ¬
function greet ( name : string ) {
const message = "Hello" ; // μ¬μ©λμ§ μμ
// ^^^^^^^ 'message' is declared but its value is never read
return name ;
}
// β noUnusedParameters μλ¬
function add ( a : number , b : number ) {
// ^ 'b' is declared but its value is never read
return a ;
}
// β
μλμ μΌλ‘ 무μν λλ _ μ¬μ©
function onClick ( _event : MouseEvent ) {
console . log ( "Clicked!" );
}
μ¬μ©νμ§ μλ νλΌλ―Έν°λ _λ‘ μμνλ©΄ κ²½κ³ κ° λ°μνμ§ μμ΅λλ€.
λͺ¨λ κ²½λ‘μμ return νμ {
"noImplicitReturns" : true
}
μμ: // β μλ¬ λ°μ
function getStatus ( code : number ) : string {
if ( code === 200 ) {
return "OK" ;
} else if ( code === 404 ) {
return "Not Found" ;
}
// ^^^^ Not all code paths return a value
}
// β
λͺ¨λ κ²½λ‘μμ return
function getStatus ( code : number ) : string {
if ( code === 200 ) {
return "OK" ;
} else if ( code === 404 ) {
return "Not Found" ;
}
return "Unknown" ;
}
// β
λλ λͺ
μμ μλ¬
function getStatus ( code : number ) : string {
if ( code === 200 ) {
return "OK" ;
} else if ( code === 404 ) {
return "Not Found" ;
}
throw new Error ( `Unknown status code: ${ code } ` );
}
Switchλ¬Έ Fallthrough λ°©μ§ {
"noFallthroughCasesInSwitch" : true
}
μμ: // β μλ¬ λ°μ
function getDay ( day : number ) : string {
switch ( day ) {
case 0 :
return "Sunday" ;
case 1 :
console . log ( "Monday" );
// ^^^^ Fallthrough case in switch
case 2 :
return "Tuesday" ;
default :
return "Unknown" ;
}
}
// β
break λλ return μΆκ°
function getDay ( day : number ) : string {
switch ( day ) {
case 0 :
return "Sunday" ;
case 1 :
console . log ( "Monday" );
return "Monday" ; // λλ break;
case 2 :
return "Tuesday" ;
default :
return "Unknown" ;
}
}
catch λΈλ‘ λ³μλ unknown {
"useUnknownInCatchVariables" : true
}
μμ: try {
throw new Error ( "Something went wrong" );
} catch ( error ) {
// errorλ unknown νμ
// β μλ¬ λ°μ
console . log ( error . message );
// ^^^^^ Object is of type 'unknown'
// β
νμ
κ°λ μ¬μ©
if ( error instanceof Error ) {
console . log ( error . message );
}
// β
νμ
λ¨μΈ (νμ€ν κ²½μ°λ§)
const err = error as Error ;
console . log ( err . message );
}
any λμ unknownμ μ¬μ©νλ©΄ νμ
체ν¬λ₯Ό κ°μ ν μ μμ΅λλ€.
λ°°μ΄/κ°μ²΄ μ κ·Ό μ undefined μ²΄ν¬ {
"noUncheckedIndexedAccess" : true
}
μμ: const users = [ "Alice" , "Bob" ];
// β μλ¬ λ°μ (noUncheckedIndexedAccess)
const firstUser = users [ 0 ];
// ^^^^^^^^^ Type 'string | undefined'
const name = firstUser . toUpperCase ();
// ^^^^^^^^^^^ Object is possibly 'undefined'
// β
undefined 체ν¬
const firstUser = users [ 0 ];
if ( firstUser !== undefined ) {
const name = firstUser . toUpperCase ();
}
// β
Optional 체μ΄λ
const name = users [ 0 ]?. toUpperCase ();
// β
Non-null assertion (νμ€ν κ²½μ°λ§)
const name = users [ 0 ] ! . toUpperCase ();
// κ°μ²΄λ λ§μ°¬κ°μ§
type UserMap = { [ key : string ] : string };
const userMap : UserMap = { alice: "Alice" };
const user = userMap [ "alice" ];
// ^^^^ Type 'string | undefined'
μ΄ μ΅μ
μ λͺ¨λ λ°°μ΄/κ°μ²΄ μ κ·Όμ T | undefinedλ‘ λ§λλλ€. λ§μ μ½λ μμ μ΄ νμν μ μμ΅λλ€.
λ μ격ν μ΅μ
(μ ν)
νμμ λ°λΌ μΆκ°ν μ μλ μ΅μ
λ€μ
λλ€.
{
"compilerOptions" : {
"noPropertyAccessFromIndexSignature" : true ,
"exactOptionalPropertyTypes" : true ,
"noUncheckedSideEffectImports" : true
}
}
noPropertyAccessFromIndexSignature
μΈλ±μ€ μκ·Έλμ²λ λκ΄νΈλ‘λ§ μ κ·Ό interface Options {
[ key : string ] : string ;
}
const options : Options = { color: "red" };
// β μλ¬ λ°μ
const color = options . color ;
// β
λκ΄νΈ μ¬μ©
const color = options [ "color" ];
μΈμ μ¬μ©:
λμ νλ‘νΌν° μ κ·Όμ λͺ
μμ μΌλ‘ λ§λ€κ³ μΆμ λ
exactOptionalPropertyTypes
Optional νλ‘νΌν°λ undefinedλ§ νμ© interface User {
name ?: string ;
}
// β μλ¬ λ°μ
const user : User = { name: undefined };
// β
νλ‘νΌν° μλ΅
const user : User = {};
// β
λͺ
μμ undefined νμ©νλ €λ©΄
interface User {
name : string | undefined ;
}
μΈμ μ¬μ©:
Optionalκ³Ό | undefinedλ₯Ό μ격ν ꡬλΆνκ³ μΆμ λ
λ§μ λΌμ΄λΈλ¬λ¦¬μ νΈνμ± λ¬Έμ κ° μμ μ μμ΅λλ€.
νμ
μ²΄ν¬ λΉνμ±ν
νΉμ μν©μμ νμ
체ν¬λ₯Ό μ°νν΄μΌ ν λκ° μμ΅λλ€.
νμΌ μ 체
ν μ€
νμ
λ¨μΈ
// @ts-nocheck
// μ΄ νμΌμ λͺ¨λ νμ
μ²΄ν¬ λ¬΄μ
const value = "hello" ;
value = 123 ; // μλ¬ λ°μ μ ν¨
// @ts-ignore
const value = someUntypedLibrary ();
// λλ μλ¬ μ€λͺ
μΆκ°
// @ts-expect-error - μΈλΆ λΌμ΄λΈλ¬λ¦¬ νμ
λΆμΌμΉ
const value = someUntypedLibrary ();
@ts-ignore λμ @ts-expect-errorλ₯Ό μ¬μ©νλ©΄ μλ¬κ° μ€μ λ‘ λ°μνμ§ μμ λ κ²½κ³ λ₯Ό λ°μ μ μμ΅λλ€.
// asλ₯Ό μ¬μ©ν νμ
λ¨μΈ
const value = someValue as string ;
// Non-null assertion
const element = document . getElementById ( "root" ) ! ;
// Double assertion (μ΅νμ μλ¨)
const value = someValue as unknown as TargetType ;
νμ
λ¨μΈμ νμ
μμ μ±μ κΉ¨λ¨λ¦½λλ€. μ λ§ νμ€ν κ²½μ°μλ§ μ¬μ©νμΈμ.
κΆμ₯ μ€μ
μ κ· νλ‘μ νΈ
κΈ°μ‘΄ νλ‘μ νΈ
λΌμ΄λΈλ¬λ¦¬
{
"compilerOptions" : {
// Sonamu κΈ°λ³Έ μ€μ μ¬μ©
"strict" : true ,
"noUnusedLocals" : true ,
"noUnusedParameters" : true ,
"noImplicitReturns" : true ,
"noFallthroughCasesInSwitch" : true ,
"useUnknownInCatchVariables" : true ,
"noUncheckedIndexedAccess" : true
}
}
μ κ· νλ‘μ νΈλ λͺ¨λ μ΅μ
μ νμ±ν νμΈμ. {
"compilerOptions" : {
"strict" : true ,
// μ μ§μ μΌλ‘ μΆκ°
// "noUnusedLocals": true,
// "noUncheckedIndexedAccess": true
}
}
κΈ°μ‘΄ νλ‘μ νΈλ μ μ§μ μΌλ‘ μ΅μ
μ μΆκ° νμΈμ. μΆμ² μμ:
strict: true
noUnusedLocals, noUnusedParameters
noImplicitReturns
noUncheckedIndexedAccess (λ§μ μμ νμ)
{
"compilerOptions" : {
"strict" : true ,
"declaration" : true ,
"declarationMap" : true ,
"noUnusedLocals" : true ,
"noUnusedParameters" : true
}
}
λΌμ΄λΈλ¬λ¦¬λ νμ
μ μ μμ± λ νμμ
λλ€.
μ±λ₯ κ³ λ €μ¬ν
νμ
μ²΄ν¬ μ΅μ
μ΄ λ§μμλ‘ μ»΄νμΌ μκ°μ΄ μ¦κ°ν μ μμ΅λλ€.
νμ
μ²΄ν¬ μλ ν₯μ
{
"compilerOptions" : {
"skipLibCheck" : true , // node_modules νμ
μ²΄ν¬ μλ΅
"incremental" : true , // μ¦λΆ μ»΄νμΌ
"tsBuildInfoFile" : ".tsbuildinfo"
}
}
skipLibCheck
node_modulesμ .d.ts νμΌμ 체ν¬νμ§ μμ
μ»΄νμΌ μκ° ν¬κ² λ¨μΆ
Sonamu κΈ°λ³Έ νμ±ν
incremental
λ³κ²½λ νμΌλ§ μ¬μ»΄νμΌ
.tsbuildinfo νμΌμ μΊμ μ μ₯
λ€μ λ¨κ³