在typescript中扩展联合类型别名?

dur*_*lka 7 typescript

我试图在编译时将某些字符串字段限制为仅某些值.问题是这些值应该是可扩展的.这是一个简化的例子:

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
}
Run Code Online (Sandbox Code Playgroud)

错误是

类型'Foobarbaz'不满足约束'Foobar'.类型'"BAZ"'不能分配给'Foobar'类型.

所以问题是:在打字稿中我如何才能将'type'限制为仅限某些字符串,但是可以使用其他字符串扩展吗?或者这是一个XY问题,有一个明显更好的解决方案?

打字稿2.3.4但我认为如果那里有魔力我可以升级到2.4.

jca*_*alz 12

我认为你在与关键字的extends含义不同的意义上使用"可扩展"这个词.按说类型是"可扩展"你说你想成为能够扩大类型接受更多的价值.但是当某种extends类型的东西时,它意味着你缩小类型以接受更少的值.

SomeInterface<T extends Foobar> 基本上只能是以下四种类型中的一种:

  • SomeInterface<'FOO'|'BAR'>:amember可以是'FOO''BAR'
  • SomeInterface<'FOO'>:amember可以只'FOO'
  • SomeInterface<'BAR'>:amember可以只'BAR'
  • SomeInterface<never>:amember不能采取任何价值

我有点怀疑这实际上是你想要的,但只有你肯定知道.


在另一方面,如果你想SomeInterface<T>进行定义,从而T可以始终是无论是FOOBAR,但也可能是一些其他的string价值,你想要的东西,打字稿不完全提供,这将指定一个下界T.类似的东西,这是无效的TypeScript.SomeInterface<TsuperFoobar extends string>

但你可能只关心它的类型amember,而不是T.如果你想amember成为或者,FOO或者BAR也可能是其他一些string值,你可以像这样指定它:

interface SomeInterface<T extends string = never> {
  amember: Foobar | T;
  [key: string]: string; 
}
Run Code Online (Sandbox Code Playgroud)

T你想要允许的额外文字的联合在哪里.如果你不想允许任何额外的,使用never,或者只是省略type参数(因为我把它never作为默认值).

让我们看看它的实际效果:

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'
Run Code Online (Sandbox Code Playgroud)

我回答你的问题了吗?希望有所帮助.


Dom*_*Dom 7

为了实现您的需要,您可以通过符号使用交集&

type Foobar = 'FOO' | 'BAR';
type FoobarBaz = Foobar | & 'BAZ'; // or: 'BAZ' | & Foobar
Run Code Online (Sandbox Code Playgroud)

相交类型示例

  • “&amp;”符号实际上是不必要的。剥离它会产生相同的类型。 (4认同)