Declaring And Invoking Functions
-
語彙
- parameter
- 関数の動作に必要なもの
- 仮引数
- argument
- 関数の起動に必要なもの
- 実引数
Optional and Default Parameters
-
オプショナル引数よりもデフォルト引数を使おう
- 末尾以外でも使える
- 型推論が効く
Rest Parameters
-
語彙
- fixed-arity
- 固定長引数の
- variadic
- 任意長引数の
- 【補】引数の数に応じて monadic, diadic, triadic, … と呼んだりする
- 固定長ではなく任意長引数にしたいことがある
arguments
は型安全じゃないのでやめよう
function sum() {
return Array
.from(arguments)
.reduce((total, n) => total + n, 0)
} // any
sum(1, 2, 3) // Error: Expected 0 arguments, but got 3.
- こうする
function sum(...numbers: number[]) {
return numbers
.reduce((total, n) => total + n, 0)
} // return type numberも推論される
sum(1, 2, 3)
- 【補】最低引数長の指定可
function sum(...numbers: [number, ...number[]]) {
return numbers
.reduce((total, n) => total + n, 0)
}
sum() // Error: Expected at least 2 arguments, but got 0.
sum(1)
sum(1,2)
call, apply, and bind
TSC Flag: strictBindCallApply
function withUnit(num: number, unit: string) {
return `${num} ${unit}`;
}
withUnit(10, 'cm');
withUnit.call(null, 10, 20); // Error: Argument of type '20' is not assignable to parameter of type 'string'.
withUnit.call(null, 10, 'cm');
withUnit.apply(null, [10, 20]); // Error: Type 'number' is not assignable to type 'string'.
withUnit.apply(null, [10, 'cm']);
withUnit.bind(null, 10, 20)(); // Error: No overload matches this call.
withUnit.bind(null, 10, 'cm')();
- 賢く型推論される
Typing this
TSC Flag: noImplicitThis
- thisはメソッド呼び出しのときにセットされる
const x = {
a() {
return this
}
}
console.log(x.a()) // { a: [Function: a] }
const a = x.a
console.log(a()) // undefined
console.log(a.call(x)) // { a: [Function: a] }
- thisのセットし忘れを取り締まれる
function month(this: Date) {
return this.getMonth()
}
month(); // Error: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Date'.
month.call(new Date);
Generator Functions
- 無限リストとかを実現できるやつ
function* createFibonacciGenerator() {
let a = 0
let b = 1
for (; ;) {
yield a;
[a, b] = [b, a + b]
}
}
const fibonacciGenerator = createFibonacciGenerator() // Generator<number, void, unknown>
console.log(fibonacciGenerator.next()) // IteratorResult<number, void>
console.log(fibonacciGenerator.next())
console.log(fibonacciGenerator.next())
Iterators
-
Generatorの異なる側面
- Generatorは値のストリームを生成する方法
- Iteratorはその値を消費する方法
-
iterable
Symbol.iterator
プロパティを持つ任意のオブジェクト- iteratorを返す関数
-
iterator
next
メソッドをもつ任意のオブジェクトvalue
プロパティとdone
プロパティを持つオブジェクトを返す- 先の例でいう
IteratorResult<number, void>
- ジェネレータ関数の戻り値がこれ
- 先の例でいう
Generator<number, void, unknown>
const xs = [1, 2, 3]; // Array is iterable
const iteratorCreater = xs[Symbol.iterator] // () => IterableIterator<number>
const iterator = iteratorCreater() // IterableIterator<number>
const result = iterator.next() // IteratorResult<number, any>
-
iterableでできること
- for-of
- スプレッド演算
- 分割代入
TSC Flag: downlevelIteration
- ES2015よりも古い環境でカスタムイテレータを動かすためのフラグ
- 無効にすることでバンドルサイズを抑えられる
Call Signatures
const add = function(a: number, b: number) {
return a + b
} // (a: number, b: number) => number
- ここで、仮引数名はドキュメンテーションとしての意味しかない
let add: (apple: number, banana: number) => number;
add = function(a: number, b: number) {
return a + b
}
Contextual Typing
function times(
f: (index: number) => void,
n: number
) {
for (let i = 0; i < n; i++) {
f(i)
}
}
times(n => console.log(n), 4)
times
がf: (index: number) => void
を要求しているので、コールバックが(n: number) => void
に推論される- インラインで定義しないとこの推論は行われない
function times(
f: (index: number) => void,
n: number
) {
for (let i = 0; i < n; i++) {
f(i)
}
}
const log = n => console.log(n) // Error: Parameter 'n' implicitly has an 'any' type.
times(log, 4)
Overloaded Function Types
type Reservation = object
type Reserve = (from: Date, to: Date, destination: string) => Reservation
- これは下記の型定義と等価
type Reservation = object
type Reserve = {
(from: Date, to: Date, destination: string): Reservation
}
- 後者の書き方で関数のオーバロードを表現できる
type Reservation = object
type Reserve = {
(from: Date, to: Date, destination: string): Reservation
(from: Date, destination: string): Reservation
}
const reserve: Reserve = (
from: Date,
toOrDestination: Date | string,
destination?: string
) => {
// ...
return {}
}
- 関数宣言をオーバロードしたいときはこう
function createElement(tag: 'a'): HTMLAnchorElement
function createElement(tag: 'canvas'): HTMLCanvasElement
function createElement(tag: 'table'): HTMLTableElement
function createElement(tag: 'a' | 'canvas' | 'table') {
if (tag === 'a') return new HTMLAnchorElement
if (tag === 'canvas') return new HTMLCanvasElement
if (tag === 'table') return new HTMLTableElement
const n: never = tag
return n
}
const anchor = createElement('a')
const canvas = createElement('canvas')
const table = createElement('table')
Column: Keeping Overload Signatures Specific
const reserve: Reserve = (
from: Date,
toOrDestination: any,
destination?: string
) => {
// ...
return {}
}
- こういうのはやめようね、という話
英語
-
terse
- 簡潔な
-
flip side
- 異なる側面