键入“除...之外的每个可能的字符串值”

Mar*_*mer 28 typescript

是否可以定义一种类型,该类型可以分配除少数指定字符串值之外的每个字符串值?我想按照这个(非编译)例子来表达一些东西:

type ReservedNames = "this" | "that"
type FooName = string - ReservedNames;
const f1 : FooName = "This" // Works
const f2 : FooName = "this" // Should error
Run Code Online (Sandbox Code Playgroud)

Tit*_*mir 13

这个问题没有通用的解决方案,因为没有办法在打字稿类型系统中表达字符串可以是除列表之外的任何值的事实。(人们可能认为条件类型Exclude<string, ReservedNames>会起作用,但事实并非如此,它只是计算回 string)。

作为一种解决方法,如果我们有一个函数并且我们特别希望不允许传入某些常量,我们可以使用条件类型来检查ReservedNames,如果传入的参数是ReservedNames这样的,则输入输入参数实际上不可能满足(使用交集类型)。

type ReservedNames = "this" | "that"
type FooName = Exclude<string, ReservedNames>;
const f1 : FooName = "This" // Works
const f2 : FooName = "this" // One might expect this to work but IT DOES NOT as FooName is just evaluates to string


function withName<T extends string>(v: T & (T extends ReservedNames ? "Value is reserved!": {})) {
  return v;
}

withName("this"); // Type '"this"' is not assignable to type '"Value is reserved!"'.
withName("This") // ok
Run Code Online (Sandbox Code Playgroud)

操场

  • 也许这在某一点上有效,但不再有效:https://www.typescriptlang.org/play/#code/C4TwDgpgBAShDOEBOA3CATAcgQwLYKgF4oAiYACwEt4SoAfUi7YEgKFEigDEB7HnfESgBRAB4BjADYBXdBAA88YEkoA7AOYAaWAmRoseBAD4A3K3E9VSqADMAjFABc3Pg OjESAFSo0oAej8oAHUeJABreHNLaxsAJicXfkMhMh9aAKgAZXIeaUl0KGQkUKA (2认同)
  • @maxedison我想我在答案中明确指出,带有变量方法的“排除”不起作用(从来没有,当否定类型出现时可能起作用)。起作用的部分是函数方法。使这一点更加明确,对于造成的混乱表示歉意。还添加了游乐场链接 (2认同)
  • 上面的例子效果很好,最后我使用了 `T &amp; (T extends ReserveNames ? never : T)`。非常感谢! (2认同)

cca*_*ton 13

这目前在 Typescript 中是不可能的,但是如果您将具体的字符串值添加为FooName.

type ReservedNames = "this" | "that"
type NotA<T> = T extends ReservedNames ? never : T
type NotB<T> = ReservedNames extends T ? never : T
type FooName<T> = NotA<T> & NotB<T>

const f1: FooName<'This'> = 'This' // works
const f2: FooName<'this'> = 'this' // error

const f3: FooName<string> = 'this' //error
const f4: FooName<any> = 'this' // error
const f5: FooName<unknown> = 'this' // error
Run Code Online (Sandbox Code Playgroud)

如果您在字符串值上使函数通用,则在函数中它会按预期工作:

function foo<T extends string> (v: FooName<T>) {
  ...
}

foo('this') // error
foo('This') // works
Run Code Online (Sandbox Code Playgroud)

  • 需要明确的是:f3、f4 和 f5 在任何分配上都会失败... f3: FooName&lt;string&gt; = 'hello'; 不确定这是否符合OP的预期,但我希望能够允许除保留字之外的所有字符串。 (3认同)