输入“除...以外的所有可能的字符串值”

时间:2018-07-20 12:05:19

标签: typescript

是否可以定义一个类型,该类型可以分配除少数几个指定的字符串值之外的所有字符串值?我想根据这个(未编译的)示例表达一些东西:

type ReservedNames = "this" | "that"
type FooName = string - ReservedNames;
const f1 : FooName = "This" // Works
const f2 : FooName = "this" // Should error

3 个答案:

答案 0 :(得分:4)

如果将具体的字符串值作为模板参数添加到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

并且在函数中,您仍然可以仅通过对函数进行模版化就可以在不知道其值的参数上使用它。

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

foo('this') // error
foo('This') // works

答案 1 :(得分:1)

对于此问题没有通用的解决方案,因为没有办法在打字稿类型系统中表达字符串可以是除列表以外的任何值的事实。 (有人可能会认为条件类型// https://github.com/uxitten/polyfill/blob/master/string.polyfill.js // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart if (!String.prototype.padStart) { String.prototype.padStart = function padStart(targetLength,padString) { targetLength = targetLength>>0; //truncate if number or convert non-number to 0; padString = String((typeof padString !== 'undefined' ? padString : ' ')); if (this.length > targetLength) { return String(this); } else { targetLength = targetLength-this.length; if (targetLength > padString.length) { padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed } return padString.slice(0,targetLength) + String(this); } }; } 可以起作用,但不会起作用,它只返回字符串即可。)

作为一种变通方法,如果我们有一个函数,并且我们特别希望不允许传入某些常量,我们可以使用条件类型来检查Exclude<string, ReservedNames>,并且如果传入的参数为{{ 1}},然后以实际上无法满足的方式键入输入参数(使用交集类型)。

ReservedNames

答案 2 :(得分:0)

我用以下方法解决了这个问题:

  1. 创建一个键为 Literals 的对象,它是文字的联合。
  2. 从对象中省略 ExcludedLiterals 类型中的任何文字,它是 Literals 的子集。
  3. 返回对象的 keyof 分辨率。
type OmitLiteral<Literals extends string | number, ExcludedLiterals extends Literals> = keyof Omit<{ [Key in Literals]: never }, ExcludedLiterals>;

有点复杂,但它有效。

type BaseUnion = "abc" | "def" | "ghi"; // "abc" | "def" | "ghi"
type OmittedUnion = OmitLiteral<BaseUnion, "ghi">; // "abc" | "def"