在 TypeScript 中扩展联合类型别名? [英] Extending Union Types Alias in TypeScript?
问题描述
我试图在编译时将某些字符串字段限制为仅包含某些值.问题是这些值应该是可扩展的.这是一个简化的示例:
I'm trying to limit some string fields to be only of certain values at compile time. The problem is that those values should be extendable. Here's a simplified example:
type Foobar = 'FOO' | 'BAR';
interface SomeInterface<T extends Foobar> {
amember: T;
[key: string]: string; // this really has to stay
}
// let's test it
const yes = {
amember: 'FOO'
} as SomeInterface<'FOO'>; // compiles as expected
// const no = {
// amember: 'BAZ'
// } as SomeInterface<'BAZ'>; // Type '"BAZ"' does not satisfy the constraint 'Foobar' as expected
// so far so good
// Now the problem
abstract class SomeClass<T extends Foobar> {
private anotherMember: SomeInterface<T>;
}
type Foobarbaz = Foobar | 'BAZ';
class FinalClass extends SomeClass<Foobarbaz> { //no good anymore
}
错误是
类型Foobarbaz"不满足约束Foobar".类型'"BAZ"' 不能分配给类型 'Foobar'.
Type 'Foobarbaz' does not satisfy the constraint 'Foobar'. Type '"BAZ"' is not assignable to type 'Foobar'.
所以问题是:如何在打字稿中将类型"限制为仅包含某些字符串,但可以扩展到其他字符串?或者这是一个 XY 问题并且有明显更好的解决方案?
So the question is: how in typescript can I limit a 'type' to be of certain strings only, but have it extendable with other strings? Or is this an XY problem and there's an obvious better solution?
Typescript 2.3.4 但我想如果有魔法的话我可以升级到 2.4.
Typescript 2.3.4 but i think i can upgrade to 2.4 if there's magic there.
推荐答案
我认为您使用的可扩展"一词与关键字 extends
的含义不同.通过说类型是可扩展的",您是说您希望能够扩大类型以接受更多值.但是当某些东西扩展
一个类型时,这意味着你正在缩小类型以接受更少的值.
I think you're using the word "extendable" in a different sense from what the keyword extends
means. By saying the type is "extendable" you're saying you'd like to be able to widen the type to accept more values. But when something extends
a type, it means that you are narrowing the type to accept fewer values.
SomeInterface
本质上只能是以下四种类型之一:
SomeInterface<T extends Foobar>
can essentially be only one of the following four types:
SomeInterface<'FOO'|'BAR'>
:amember
可以是'FOO'
或'BAR'
SomeInterface<'FOO'>
:amember
只能是'FOO'
SomeInterface<'BAR'>
:amember
只能是'BAR'
SomeInterface
:amember
不能取任何值
SomeInterface<'FOO'|'BAR'>
:amember
can be either'FOO'
or'BAR'
SomeInterface<'FOO'>
:amember
can be only'FOO'
SomeInterface<'BAR'>
:amember
can be only'BAR'
SomeInterface<never>
:amember
cannot take any value
我有点怀疑这是否真的是你想要的,但只有你自己知道.
I kind of doubt that's actually what you want, but only you know that for sure.
另一方面,如果您希望 SomeInterface
被定义为 T
可以总是是 FOO
或 BAR
,但也可能是其他一些 string
值,你想要一些 TypeScript 没有完全提供的东西,这将指定 T
.类似于 SomeInterface<T
super
Foobar extends string>
,这是无效的 TypeScript.
On the other hand, if you want SomeInterface<T>
to be defined such that T
can always be either FOO
or BAR
, but also possibly some other string
values, you want something that TypeScript doesn't exactly provide, which would be specifying a lower bound for T
. Something like SomeInterface<T
super
Foobar extends string>
, which isn't valid TypeScript.
但你可能只关心 amember
的类型,而不是 T
.如果您希望 amember
成为 FOO
或 BAR
,但也可能是其他一些 string
值,您可以指定像这样:
But you probably only care about the type of amember
, and not T
. If you want amember
to be either FOO
or BAR
, but also possibly some other string
values, you could specify it like this:
interface SomeInterface<T extends string = never> {
amember: Foobar | T;
[key: string]: string;
}
其中 T
只是您希望允许的额外文字的联合.如果您不想允许任何额外内容,请使用 never
,或仅省略类型参数(因为我已将 never
设为默认值).
where T
is just the union of extra literals you'd like to allow. If you don't want to allow any extra, use never
, or just leave out the type parameter (since I've put never
as the default).
让我们看看它的实际效果:
Let's see it in action:
const yes = {
amember: 'FOO'
} as SomeInterface; // good, 'FOO' is a Foobar
const no = {
amember: 'BAZ'
} as SomeInterface; // bad, 'BAZ' is not a Foobar
abstract class SomeClass<T extends string> {
private anotherMember: SomeInterface<T>;
}
class FinalClass extends SomeClass<'BAZ'> {
} // fine, we've added 'BAZ'
// let's make sure we did:
type JustChecking = FinalClass['anotherMember']['amember']
// JustChecking === 'BAZ' | 'FOO' | 'BAR'
<小时>
我回答你的问题了吗?希望有所帮助.
Did I answer your question? Hope that helps.
这篇关于在 TypeScript 中扩展联合类型别名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!