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

huangapple go评论75阅读模式
英文:

Type checking with omit params

问题

I'm trying to define some type based on a base Type.

  • 'Simple' Type has a name and type property
  • 'Base' Type has a property name that cannot be 'text' or 'radio'
  • I create a 'Radio' and a 'Texto' type

But when I create an object with type: 'radio', it does not make mandatory the 'radio' or 'freq' properties...

I don't know why...

Can someone can highlight the issue please ?

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'
}
英文:

I'm trying to define some type based on a base Type.

  • 'Simple' Type has a name and type property
  • 'Base' Type has a property name that cannot be 'text' or 'radio'
  • I create a 'Radio' and a 'Texto' type

But when I create an object with type: 'radio', it does not make mandatory the 'radio' or 'freq' properties...

I don't know why...

Can someone can highlight the issue please ?

type Simple = {
    name: string
    type: string
}

type Base = Exclude&lt;Simple, {type: &#39;text&#39;|&#39;radio&#39;}&gt;

type Radio = Base &amp; {
    type: &#39;radio&#39;,
    radio: string,
    freq: string
};

type Texto = Base &amp; {
    type: &#39;text&#39;
    label: string
}

type Field = Radio | Texto | Base

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

答案1

得分: 1

以下是翻译好的内容:

在TypeScript中,没有特定的类型对应于所有string值,除了"text""radio"之外,因此您无法为Base指定一个可以将其与TextoRadio区分开的特定类型。这将需要所谓的“否定类型”,如在microsoft/TypeScript#29317中实现但从未发布。因此,您不能说string & not ("text" | "radio")Exclude实用程序类型只能过滤联合类型,但既不是string也不是Simple都不是联合类型,所以它没有任何效果。


在没有能够按您希望的方式工作的特定类型的情况下,您可以尝试使用泛型类型,并使用它来约束输入值。所以,不是像 const myRadio: Field = {⋯} 这样写,您需要写成 const myRadio: Field<"radio"> = {⋯}。或者,如果您不想手动写类型参数,您可以编写一个实用函数来推断类型参数,然后写成 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> 是一个条件类型,根据需要使用 T 作为区分类型来区分 KnownField(使用 Extract 实用程序类型),否则回退到 Simple。而 field() 是一个辅助函数,为您提供所需的类型推断。

让我们尝试一下:

const myRadio = field({
    type: 'radio',
    name: 'snig'
}); // 错误!
//   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

看起来很不错。

代码示例链接

希望这有所帮助!

英文:

There's no specific type in TypeScript that corresponds to all string values except &quot;text&quot; and &quot;radio&quot;, so you can't give Base a specific type that distinguishes it from Texto or Radio. That would require so-called negated types as implemented in microsoft/TypeScript#29317 but never released. So you can't say string &amp; not (&quot;text&quot; | &quot;radio&quot;). The Exclude utility type can only filter union types but since neither string nor Simple are union types, it has no effect.


In the absence of specific types that work the way you want, you could try a generic type and use it to constrain the input values. So instead of const myRadio: Field = {⋯}, you'd need to write something like const myRadio: Field&lt;&quot;radio&quot;&gt; = {⋯}. Or, if you don't want to manually write that type argument, you could write a utility function to infer the type argument, and instead write const myRadio= field({⋯}) and myRadio will have its type inferred as Field&lt;&quot;radio&quot;&gt;. It could look like this:

type KnownField = Radio | Texto;

type Field&lt;T extends string&gt; =
    T extends KnownField[&#39;type&#39;] ?
    Extract&lt;KnownField, { type: T }&gt; :
    Simple;

const field = &lt;T extends (string &amp; {}) | KnownField[&#39;type&#39;]&gt;(
    t: { type: T } &amp; Field&lt;T&gt;
): Field&lt;T&gt; =&gt; t;

Here Field&lt;T&gt; is implemented as a conditional type that discriminates KnownField using T as a discriminant if it applies (using the Extract utility type, or else falling back to Simple. And field() is a helper function that gives you the inference you want.

Let's try it:

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

That's the error you wanted. And if you inspect myRadio, its type is Radio. The following code compiles with no errors:

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

Looks good.


Playground link to code

huangapple
  • 本文由 发表于 2023年6月4日 23:32:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76401144.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定