英文:
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<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'
}
答案1
得分: 1
以下是翻译好的内容:
在TypeScript中,没有特定的类型对应于所有string
值,除了"text"
和"radio"
之外,因此您无法为Base
指定一个可以将其与Texto
或Radio
区分开的特定类型。这将需要所谓的“否定类型”,如在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 "text"
and "radio"
, 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 & not ("text" | "radio")
. 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<"radio"> = {⋯}
. 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<"radio">
. It could look like this:
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;
Here Field<T>
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: 'radio',
name: 'snig'
}); // error!
// Type '{ type: "radio"; name: string; }' is missing the following properties from type
// '{ type: "radio"; radio: string; freq: string; }': 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: "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
Looks good.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论