typescript 使用省略参数进行类型检查

niwlg2el  于 2023-06-07  发布在  TypeScript
关注(0)|答案(1)|浏览(253)

我试图定义一些基于基本类型的类型。

  • “简单”类型具有名称和类型属性
  • “Base”类型的属性名不能是“text”或“radio”
  • 我创建了一个'Radio'和一个'Texto'类型

但是当我创建一个类型为:'radio',它不强制'radio'或'freq'属性...
我不知道为什么
有人能强调一下这个问题吗?

type Simple = {
    name: string
    type: string
}

type Base = Exclude<Simple, {type: 'text'|'radio'}>

type Radio = Base & {
    type: 'radio',
    radio: string,
    freq: string
};

type Texto = Base & {
    type: 'text'
    label: string
}

type Field = Radio | Texto | Base

/**
 * I expect to see an error thrown with 'freq' and 'radio' is missing here...
 */
const myRadio:Field = {
    type: 'radio',
    name:'snig'
}
ymzxtsji

ymzxtsji1#

在TypeScript中,除了"text""radio"之外,没有对应于所有string值的特定类型,所以你不能给予Base一个特定的类型来区分它与TextoRadio。这将需要所谓的 * 否定类型 *,如在microsoft/TypeScript#29317中实现的,但从未发布。所以你不能说string & not ("text" | "radio")Exclude实用程序类型只能过滤联合类型,但由于stringSimple都不是联合类型,因此它没有效果。
如果没有特定的类型可以按照您想要的方式工作,您可以尝试generic类型并使用它来 * 约束 * 输入值。因此,您需要编写类似const myRadio: Field<"radio"> = {⋯}的代码,而不是const myRadio: Field = {⋯}。或者,如果你不想手动编写类型参数,你可以编写一个实用函数来 * 推断 * 类型参数,而不是写const myRadio= field({⋯})myRadio将其类型推断为Field<"radio">。它可以看起来像这样:

type KnownField = Radio | Texto;

type Field<T extends string> =
    T extends KnownField['type'] ?
    Extract<KnownField, { type: T }> :
    Simple;

const field = <T extends (string & {}) | KnownField['type']>(
    t: { type: T } & Field<T>
): Field<T> => t;

这里,Field<T>被实现为conditional type,它使用T作为判别式来判别KnownField(如果适用的话)(使用Extract实用程序类型,否则回退到Simple)。field()是一个辅助函数,它可以提供您想要的推断。
让我们试试看:

const myRadio = field({
    type: 'radio',
    name: 'snig'
}); // error!
//   Type '{ type: "radio"; name: string; }' is missing the following properties from type
//  '{ type: "radio"; radio: string; freq: string; }': radio, freq

这就是你想要的错误。如果检查myRadio,则其类型为Radio。下面的代码编译时没有错误:

const t = field({ type: "text", name: "abc", label: "abc" });
// const t: Texto
const r = field({ type: "radio", name: "abc", radio: "abc", freq: "abc" });
// const r: Radio
const s = field({ type: "random", name: "abc" });
// const s: Simple

看起来不错
Playground链接到代码

相关问题