Programming TypeScript ch3 (1/2)
All About Types
- 「型」
- 値とそれを使ってできること(演算子とか)の集合
- 「それを使ってできること」が重要
- typecheckerでコードの不正を検出するにあたり、何をもって正しい/正しくないとするかの定義にあたる
Talking About Types
function squareOf(n: number) { return n * n }
- 語彙の確認
- assignability
n
に2
は代入できるが'z'
は代入できない
- bounds
n
のupper boundはnumber
だからnumber|string
は代入できないよ、的なやつ
- constraints
- 「
n
をnumber
にconstrainする」
- 「
- assignability
- 後の章で詳しく掘る
The ABCs of Types
any
the Godfather of types
- TypeScriptではコンパイル時にすべてが型を持つ必要があり、型情報がないときのデフォルトの型がこれになる
- 最後の手段
- 全ての値、あらゆる操作の集合だからtypecheckerで取り締まれない
column: TSC Flag: noImplicitAny
- strictルールのサブセット
- anyに推論されるヤツを怒る
unknown
- any同様、全ての値・全ての操作の集合
- anyと異なり、refinement(縮小変換)せずに特定の型を期待する操作を行うとエラーになってくれる
let a: unknown = 30 // unknown let b = a === 123 // boolean let c = a + 10 // Error TS2571: Object is type of 'unknown' if (typeof a === 'number') { let d = a + 10 // number }
- 【補】union types
let e: number|any = 10; // any let f: number|unknown = 10; // unknown let g: unknown|any = 10; // any
unknown|any
はunknown
じゃないのか…謎
boolean
let a = true // boolean var b = false // boolean const c = true // true let d: boolean = true // boolean let e: true = true // true let f: true = false // Erorr TS2322 Type 'false' is not assignable to type 'true'
c
,e
,f
のように特定のboolean値に絞るのは type literal と呼ばれる- TS独特
- プリミティブのconstは他の値をとらないことが明らかなのでtype literalに推論される
number
- boolean同様type literalが効く
bigint
- バニラJSエンジンでサポートされていなかったりするので注意する
- 【補】ECMAScript2020,the 11th editionで入るそうな。よかったね
let a = 1234n // bigint const b = 5678n // 5678n let e = 88.5n // Error TS1353 A bitint literal must be an integer.
- tsconfigのtargetのバージョンが低いと怒られる
let a = 1234n // Error TS2737 BigInt literals are not available when targeting lower than ESNext.
string
- 読み飛ばし
symbol
- ES2015でやってきたヤツ
let a = Symbol('a') // symbol let b = a === 'a' // Error: This condition will always return 'false' since the types 'symbol' and 'string' have no overlap. const e = Symbol('e') // typeof e const f: unique symbol = Symbol('f') // typeof f let g: unique symbol = Symbol('f') // Error TS1332: A variable whose type is a 'unique symbol' type must be 'const'. let h = e === e // boolean let i = e === f // Error TS2367: This condition will always return 'false' since the types 'typeof e' and 'typeof f' have no overlap.
Objects
- TSのobject型はオブジェクトの形を規定する
- TSは構造的型付け
- 特定のプロバティを持っていることだけに興味がある
- 型名に興味はない
- 「ダックタイピング」とも呼ばれるヤツ
let a: object = { b: 'x' } a.b; // Error TS2339: Property 'b' does not exist on type 'object'.
object
はany
よりはいくぶん狭い程度の型- JavaScriptのObjectであること(とnullでないこと)程度しか保証してくれない
- 【補】JavaScriptで
typeof null
が"object"
になることを揶揄していると思われる
let a = Math.random() < 0.5 ? { a: 1 } : null if (typeof a === 'object') { a // { a: number } | null } else { a // never }
let a: object = { b: 'x' } // { b: string } a.b; // string
- TypeScriptはobjectのプロパティについて厳しい
let a: { x: number } = {} // Error TS2741: Property 'x' is missing in type '{}' but required in type '{ x: number; }'. let b: { x: number } = { x: 1, y: 'hoge' // Error TS2322: Type '{ x: number; y: string; }' is not assignable to type '{ x: number; }'. } let c: { x: number, y: string } = { x: 1, y: 'hoge' } let d: { x: number, y?: string } = { x: 1, }
- プロパティにはreadonlyをつけられる
let user: { readonly firstName: string } = { firstName: 'Gauss' } user.firstName user.firstName = 'Gausss' // Error TS2540: Cannot assign to 'firstName' because it is a read-only property.
{}
アノテーションは大文字のObject
と同じような性質で、null
とundefined
以外なんでも入るので危険。使ってはいけない
let danger: {} danger = {} danger = {x: 1} danger = [] danger = 'a' danger = 1 danger = Symbol('a') danger = null // Error TS2322: Type 'null' is not assignable to type '{}'. danger = undefined // Error TS2322: Type 'undefined' is not assignable to type '{}'.
let danger: Object danger = {} danger = {x: 1} danger = [] danger = 'a' danger = 1 danger = Symbol('a') danger = null // Error TS2322: Type 'null' is not assignable to type 'Object'. danger = undefined // Error TS2322: Type 'undefined' is not assignable to type 'Object'.
- cf. 小文字の
object
let danger: object danger = {} danger = {x: 1} danger = [] danger = 'a' // Error TS2322: Type '"a"' is not assignable to type 'object'. danger = 1 // Error TS2322: Type '1' is not assignable to type 'object'. danger = Symbol('a') // Error TS2322: Type 'symbol' is not assignable to type 'object'. danger = null // Error TS2322: Type 'null' is not assignable to type 'object'. danger = undefined // Error TS2322: Type 'undefined' is not assignable to type 'object'.
- 【補】リテラル
{}
は{}
に推論されるので要注意
const a = {} // {} if (typeof a === 'object') { a // {} } else if (typeof a === 'number') { a // number } else { a // {} }
Column: Type Inference When Declaring Objects with const
const a = { b: 12 }
- これは
{ b: number }
に推論される{ b: 12 }
ではなく
- 属性はmutableですから
Column: Definite Assignment
- 定義と初期化の分離はTSでもサポートされている
- 未初期化で使おうとするとちゃんと怒ってくれる
let i: number let j = i * 3 // Error TS2741: Variable 'i' is used before being assigned.
- 型のアノテーションがなくても別件で怒ってくれる
let i let j = i * 3 // Error TS2532: Object is possibly 'undefined'.
- 【補】
any
を明示するとすり抜けちゃう
let i: any let j = i * 3 // number
- バニラJSとの互換性を考えたら、それはそう
Column: Index Signatures
- こういうやつ
let airplaneSeatingAssignments: { [seatNumber: string]: string } = { '34D': 'Jack', '34E': 'Alice' }
- (連想)配列のキーを増やせる
[key: T]: U
シンタックス- 「
T
型のキーはすべてU
型の値をもつ」 - キーはstringかnumberにassignableであること
key
は他の識別子でもかまわない
- 「
英語
- lord over
- (人に対して)いばり顔をする