TypeScirpt 中文教程之函数下----翻译自ts官方
?? 可选参数
TS实现一个可选参数只需要在参数后紧跟一个 ? 即可。例如:
function f(x?: number) { // ... } f(); // OK f(10); // OK 对于一个可选参数 x ,他拥有 number | undefined 两个类型 你可以提供一个默认值,例如: function f(x = 10) { // ... } 注意默认值是可选参数的一种特殊情况,也就是说这里的 x 类型依然是 number | undefined 这个方法可以有以下三种调用方式: f(); f(10); f(undefined); ?? 回调参数中的可选参数定义一个拥有回调函数的方法 function myForEach(arr: any[], callback: (arg: any, index?: number) => void) { for (let i = 0; i < arr.length; i++) { callback(arr[i], i); } } 你可能这样去调用,因为 index 是可选的
myForEach([1, 2, 3], (a) => console.log(a)); myForEach([1, 2, 3], (a, i) => console.log(a, i)); 但是如果callback 第二个参数不传入,某些情况下会导致无法执行的可能: function myForEach(arr: any[], callback: (arg: any, index?: number) => void) { for (let i = 0; i < arr.length; i++) { callback(arr[i]); } } myForEach([1, 2, 3], (a, i) => { console.log(a, i.toFixed()); // Object is possibly 'undefined'.Object is possibly 'undefined'. }); 在 JS 中,如果调用的函数的参数多于定义的参数,则多余的参数将被忽略。TS 的行为方式相同。
除了刻意为之,否则不要在回调函数中使用可选参数。 ?? 函数的重载
JS 函数可以在不同数量不同类型的参数下调用,比如编写一个函数:返回一个 Date 对象,可以传入一个参数:时间戳;或者三个参数:年/月/天 在 TS 中,我们通过重载签名的方式实现一个函数在不同的调用方法下实现上述需求: function makeDate(timestamp: number): Date; // 接受一个参数的重载签名 function makeDate(m: number, d: number, y: number): Date; // 接受三个参数的重载签名 function makeDate(mOrTimestamp: number, d?: number, y?: number): Date { // 最后的合体实现签名 if (d !== undefined && y !== undefined) { return new Date(y, mOrTimestamp, d); } else { return new Date(mOrTimestamp); } } const d1 = makeDate(12345678); const d2 = makeDate(5, 5, 5); 然后,我们编写了一个具有兼容签名的函数。这个函数有一个实现签名,但是这个签名不能直接按照他的字面意思调用,字面上 d, y 是可选的, 也不能按照可选参数的方式调用,不能传入两个参数进行调用。 const d3 = makeDate(1, 3); // No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments. ?? 其他类型 void 当一个函数什么都不返回的时候,这个函数的返回类型就是 void。 JS 中,却会返回 undefined。但是 void 和 undefined 是两个截然不同的类型。 函数返回void的类型,并不会强制函数不能返回其他值。 比如以下定义了几个返回类型为 void 的函数
type voidFunc = () => void;
const f1: voidFunc = () => { return true; };
const f2: voidFunc = () => true;
const f3: voidFunc = function () { return true; }; 依次调用这几个函数,
const v1 = f1(); const v2 = f2(); const v3 = f3(); console.log(v1, v2, v3) // true, true, true
可以看到依旧返回 true ,这里的 void 更趋向于语义表达某个函数没有返回值。 ?? object, 不是 Object 哦! TS 中有 object 类型,可以指向除了 (
string, number, bigint, boolean, symbol, null, undefined)类型之外的所有值。这个类型既不同于 { } ,也不同于Object 。
const fn: object = () => {
return {}
}
const arr: object = [] const s: object = new String('hah') ?? unknow , 还有一个类型叫做 unknow 。这个类型可以指向任何类型,但是不能在这个值上进行任何操作。 这个类型通常使用在函数未知的返回。例如: function safeParse(s: string): unknown { return JSON.parse(s); }
// Need to be careful with 'obj'! const obj = safeParse(someRandomString);
?? never ,当所有类型都判断完毕后,剩余的就是 never 类型 例如:
function fn(x: string | number) { if (typeof x === "string") { // do something } else if (typeof x === "number") { // do something else } else { x; // has type 'never'! } } ?? 剩余参数
在定义一个函数时当你不知道剩余参数的个数时,可以使用剩余参数定义,使用 ... 进行赋值
function multiply(n: number, ...m: number[]) { return m.map((x) => n * x); } // 'a' gets value [10, 20, 30, 40] const a = multiply(10, 1, 2, 3, 4); 使用展开运算符... 还可以直接展开所有参数,例如: const arr1 = [1,2,3];
const arr2 = [4,5,6];
arr1.push(...arr2); 请注意,通常,TS不假定数组是不可变的。这可能会导致一些令人惊讶的行为: const args = [4,5];
const angle = Math.atan2(...args);
error: A spread argument must either have a tuple type or be passed to a rest parameter.
这是因为 TS 认为数组 args 包含的元素有可能是 0 个 或者 多个,不符合 Math.atan2 参数范围 我们可以使用断言 as const 定义为不可变数据: const args = [8, 5] as const;
const angle = Math.atan2(...args); ?? 参数解构
你可以使用参数解构拆分对象实现参数的赋值:
function sum({a, b, c}) {
console.log(a + b + c);
} sum({ a: 10, b: 3, c: 9 }); 使用 TS 后:
function sum ({a, b, c}: {a: number; b: number; c: number}) {
console.log(a + b + c)
}
也可以把 type 单独拿出去:
type ABC = {a: number; b: number; c: number};
function sum({a, b, c}: ABC) {...}