如何在TypeScript中编写不包含空字符串的字符串类型

时间:2017-09-16 11:21:58

标签: typescript

TypeScript wroten的功能如下:

function propKeyMap(propKey:string):string {
  //TODO
}

propKey不能是""(空字符串)。我们可以编写一个不包含空字符串的类型吗?

1 个答案:

答案 0 :(得分:2)

简答:

不,你不能这样做。只需在运行时检查propKey值,如果为空,则抛出错误。

答案很长:

TypeScript当前(截至v2.5)缺少subtraction types,因此无法告诉编译器类型是string而不是""。但是,有一些解决方法。

您可以使用品牌(请参阅Microsoft/TypeScript #4895中的讨论)创建string的子类型,然后尝试自行强制执行非空约束,因为TypeScript可以& #39;吨。例如:

type NonEmptyString = string & { __brand: 'NonEmptyString' };

现在,您无法为string变量分配NonEmptyString值:

const nope: NonEmptyString = 'hey'; // can't assign directly

但是你可以创建一个带string并返回NonEmptyString的函数:

function nonEmptyString(str: ""): never;
function nonEmptyString(str: string): NonEmptyString;
function nonEmptyString(str: string): NonEmptyString {
  if (str === '')
    throw new TypeError('empty string passed to nonEmptyString()');
  return str as NonEmptyString;
}

如果传入空nonEmptyString(),函数string将在运行时爆炸,因此只要您使用此函数构造NonEmptyString个对象,您就是安全的。此外,如果TypeScript知道您传入空字符串的事实,则返回的对象将是never类型(本质上意味着它不应该发生)。所以它可以对空字符串进行一些编译时保护:

const okay = nonEmptyString('hey');
okay.charAt(0); // still a string

const oops = nonEmptyString(''); // will blow up at runtime
oops.charAt(0); // TypeScript knows that this is an error 

但它确实只是一个位的编译时防护,因为很多时候TypeScript没有意识到string是空的:

const empty: string = ""; // you've hidden from TS the fact that empty is ""
const bigOops = nonEmptyString(empty); // will blow up at runtime
bigOops.charAt(0); // TypeScript doesn't realize that it will blow up

不过,它总比没有好......或者可能是。最重要的是,您可能需要使用运行时检查对空字符串进行编译时断言,无论如何。

即使TypeScript本身可以将NonEmptyString表达为像string - ""这样的东西,编译器在大多数情况下也可能不够聪明,以推断出字符串操作的结果是否为一个NonEmptyString。我的意思是,我们知道两个NonEmptyString s的串联应该至少有两个长度,但我怀疑TypeScript会:

declare let x: NonEmptyString; 
declare let y: NonEmptyString; 
const secondCharBad: NonEmptyString = (x + y).charAt(1); // won't work
const secondCharGood = nonEmptyString((x + y).charAt(1)); // okay

这是因为您要求的类型接近滑坡的最顶部,直到dependent types,这对于开发人员的表达能力来说非常好,但对于编译器的可判定性并不是很好。对于非空字符串,可能在类型级别上可以做一些合理的事情,但一般来说,您仍然需要帮助编译器确定字符串实际上是非空的。

希望有所帮助。祝你好运!