首页 > 解决方案 > TypeScript 功能解构不强制执行默认类型

问题描述

我有一个接受单个对象参数的函数,如下所示。(注意,这是一个人为的例子,但它说明了问题。)

type FuncParams = { sayYes: boolean; }
type FuncType = (params: FuncParams) => string;

const maybeSayYes: FuncType = ({ sayYes }) => sayYes ? 'Yes' : 'No';

maybeSayYes({ sayYes: true }); // Returns 'Yes'
maybeSayYes({ sayYes: false }); // Returns 'No'

我想让这个sayYes属性成为可选的,所以我更新了如下类型并在函数声明中添加了一个默认值:

type FuncParams = { sayYes?: boolean; }
type FuncType = (params: FuncParams) => string;

const maybeSayYes: FuncType = ({ sayYes = true }) => sayYes ? 'Yes' : 'No';

maybeSayYes({ sayYes: true }); // Returns 'Yes'
maybeSayYes({ sayYes: false }); // Returns 'No'
maybeSayYes({}); // Returns 'Yes'

但是,我注意到我可以分配任何默认值,sayYes并且 TypeScript 不会标记不正确的类型。例如:

const maybeSayYes: FuncType = ({ sayYes = 'notABoolean' }) => sayYes ? 'Yes' : 'No';

我希望 TypeScript 能够从中推断boolean类型FuncType并阻止我分配 a string,但事实并非如此。

如果我按如下方式显式键入参数,则可以显示错误:

const maybeSayYes: FuncType = ({ sayYes = 'notABoolean' }: FuncParams) => sayYes ? 'Yes' : 'No';

但是,我假设 TypeScript 会从FuncType. 我确定这是我对 TypeScript 的理解有问题,但我想知道:

  1. 为什么 TypeScript 没有告诉我这'notABoolean'不是boolean.
  2. 如何在不必重复FuncParams输入的情况下约束默认值类型。

在 TS Playground 上复制

标签: typescript

解决方案


我对您描述的行为感到惊讶,但我对 TypeScript 的了解仍然不是很深。

您可以使用函数重载类型来做到这一点:

type FuncParams = { sayYes?: boolean; }
type FuncType = {
    (params: FuncParams): string;
    (params: FuncParams & {sayYes: never}): string; // Or just: {params: {sayYes: never}: any;
};

然后,尝试使用sayYesboolean类型的调用将匹配第二个重载并导致错误。(非常感谢jcalz指出它sayYes仍然是可选的,并且您可以使用更简单的签名来处理never重载。)

这给了你这种行为:

// Correct default value type
const maybeSayYes1: FuncType = ({ sayYes = true }) => sayYes ? 'Yes' : 'No';

// Incorrect default value type
const maybeSayYes2: FuncType = ({ sayYes = 'notABoolean' }) => sayYes ? 'Yes' : 'No';
//    ^−−−−−−−−−−−−− TypeScript compiler error here

// Correctly don't have it at all (since it's optional)
const maybeSayYes3: FuncType = ({ }) => Math.random() ? 'Yes' : 'No';

游乐场链接


推荐阅读