TypeScript 函数的默认参数为函数的类型问题

WingDust
  • 99
let f = (fn:(e:any)=>void = c) => {}
let c = ()=> 0 // 类型: () => number
// 上面的函数可以作为默认参数

// 而在下面这个就会 Error
let t = (f:number = '22') =>{}

主要是第一个为什么可以作为默认参数?
第二个大家应该都知道

回复
阅读 166
2 个回答

要注意看提示信息啊,把t改成这样就行

let t = (f:number = 22) =>{}

(e: any) 表示任意参数,包括 undefined,包含了没有参数的情况 —— 或者可以这样理解:
由于 fn 的参数是 e: any,所以在内部可以传入任意参数,当把 c 作为实参传入之后,也可以给 c() 传入任意参数,而不影响接口,也不可能影响 c 的内部行为(因为 c 压根不会使用这个参数)。如果把 c 的参数声明为 (a: any, b: any) 就不行了,因为调用 c 需要传入两个参数,而在 f 的参数 fn 声明只需要一个参数,在使用调用时就可能不会传入第 2 个参数,不符合 c 的参数要求。

fn 的类型(返回类型)是 void,说明在 f 函数体中不需要使用它的返回值,那么对传入的 fn,其实并不需要约束返回值类型。如果 fn 声明返回类型是 : string,那么 c 就不参传入,因为 c 的返回类型是 int 不符合 fn 的约束。如果允许传入 c 作为 fn,那么 f 中拿到 fn(即 c) 返回值进行后续处理的时候就可能产生类型错误(以为是 string,但实际是 number)。


我觉得说得不清楚,还是举例来得直接些:

function f(fn: (a: string) => string | number) {
    const s = "hello";  // string 类型
    const r = fn(s);    // string 类型
    return typeof r === "string"
        ? r.toUpperCase()
        : r.toFixed(2);
}

// 成功的类型匹配
f(
    // 参数类型是 fn 参数类型的超集,所以符合传入 fn 条件的参数
    // 都符合传入下面这个函数,比如 "hello" (string 类型)
    (a: string | number) => a.toString()
    // 返回类型是 string (由 .toString() 推导而来)
    // 是 fn 返回类型的子集,所以它的返回值
    // 一定可以被后续代码(就是 typeof r ...)处理
);

// 不成功的类型匹配 - 参数
f(
    // 参数类型 number 不是 fn 参数类型 string 的超集
    // 所以传递给 fn 的参数,不能给下面这个函数使用(比如 "hello")
    (a: number) => a.toString()
);

// 不成功的类型匹配 - 返回类型
f(
    (a: string) => { }
    // 该函数无返回,推导返回类型是 void,
    // 其返回值不可能给调用 fn 的后续代码使用
    // 也就是 `typeof r ...` 可能会出错,违反类型安全约束
);
你知道吗?

宣传栏