在TypeScript中,应该如何让编译器确定字符串是否为方法/函数的有效参数?
现在,我正在使用字符串字面值来实现这一点。例如,
type ValidLetter = "A" | "B" | "C" | "D"; // string literal definition
public PostLetter(letter: ValidLetter) {
...
api.post("https://example.com/letters/", letter);
// POST method only accepts "A", "B", "C", or "D"
}
PostLetter("A") // All good!
PostLetter("Z") // Compiler error唯一的问题是,在编译时,我不知道将传递给Post方法的值。我可以接收任何类型的字符串,
let a = "A";
let foobar = "foobar";
PostLetter(a) // Compiler error
PostLetter(foobar) // Compiler error我正在寻找的是一种检查字符串是否是字符串文字的有效成员的方法。我已经尝试过使用typeof、instanceof、用户定义的类型保护和强制转换。他们似乎都不具备所需的能力。
我如何确定a是ValidLetter的成员,而foobar不是?或者,也许字符串字面量不是可行的方法。
发布于 2017-07-13 08:22:53
您应该能够通过混合使用值映射以及用户定义的类型保护来做到这一点:
const ValidLetterMap = { A: 1, B: 1, C: 1, D: 1 };
type ValidLetter = keyof typeof ValidLetterMap;
declare function postLetter(letter: ValidLetter): void;
postLetter("A"); // ok
postLetter("E"); // err
const a = "A";
postLetter(a); // ok
let a$ = "A";
postLetter(a$); // err, a$ is of type string since it is mutable
function isValidLetter(letter: string): letter is ValidLetter {
return letter in ValidLetterMap;
}
if (isValidLetter(a$)) {
postLetter(a$); // now ok because we've "proven" that a$ is a valid letter
}编辑:这是一个通用的表单,依赖于一些小技巧来暴露类型。
class StringLiteral<T extends string> {
private literalSet: {[P in T]: true};
// sort of a hack so we can expose a union type of valid letters
public get typeProvider(): T {
throw new Error("typeProvider is only meant for typing info, it has no value");
}
constructor(...literals: T[]) {
this.literalSet = literals.reduce(
(acc, curr) => (acc[curr] = true, acc),
{} as {[P in T]: true}
);
}
public isValid(candidate: string): candidate is T {
return candidate in this.literalSet;
}
}
// how to use
const lettersLiteral = new StringLiteral("A", "B", "C", "D");
declare function postLetter(letter: typeof lettersLiteral.typeProvider): void;
let a$ = "A";
postLetter(a$); // not ok
if (lettersLiteral.isValid(a$)) {
postLetter(a$); // ok!!
}发布于 2017-07-13 15:02:23
TypeScript根本不做任何运行时类型检查。类型检查在编译时进行,类型信息不包括在生成的JavaScript文件中。
post.ts
type ValidLetter = "A" | "B" | "C";
function post(letter: ValidLetter) {
}生成以下JavaScript:
post.js
function post(letter) {
}因此,您必须在运行时代码中手动重新指定类型检查:
type ValidLetter = "A" | "B" | "C";
function post(letter: ValidLetter) {
if (letter !== "A" && letter !== "B" && letter !== "C") throw "error!";
}不算太坏。但这有点多余,不是吗?
有一个名为runtypes的库,它允许您指定类型一次,它会生成一个编译时TypeScript类型,并保留类型信息以进行运行时检查:
import { Literal, Union, Static } from 'runtypes'
const ValidLetter = Union(Literal('A'), Literal('B'), Literal('C'));
type ValidLetter = Static<typeof ValidLetter>;
function post(letter: ValidLetter) {
ValidLetter.check(letter);
}因此,现在您可以获得完整的编译时检查和运行时检查。
https://stackoverflow.com/questions/45068893
复制相似问题