首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使编译器检查字符串参数在Typescript中是否有效?

如何使编译器检查字符串参数在Typescript中是否有效?
EN

Stack Overflow用户
提问于 2017-07-13 07:08:09
回答 2查看 877关注 0票数 1

在TypeScript中,应该如何让编译器确定字符串是否为方法/函数的有效参数?

现在,我正在使用字符串字面值来实现这一点。例如,

代码语言:javascript
复制
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方法的值。我可以接收任何类型的字符串,

代码语言:javascript
复制
let a = "A";
let foobar = "foobar";

PostLetter(a) // Compiler error
PostLetter(foobar) // Compiler error

我正在寻找的是一种检查字符串是否是字符串文字的有效成员的方法。我已经尝试过使用typeofinstanceof、用户定义的类型保护和强制转换。他们似乎都不具备所需的能力。

我如何确定aValidLetter的成员,而foobar不是?或者,也许字符串字面量不是可行的方法。

EN

回答 2

Stack Overflow用户

发布于 2017-07-13 08:22:53

您应该能够通过混合使用值映射以及用户定义的类型保护来做到这一点:

代码语言:javascript
复制
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
}

编辑:这是一个通用的表单,依赖于一些小技巧来暴露类型。

代码语言:javascript
复制
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!!
}
票数 0
EN

Stack Overflow用户

发布于 2017-07-13 15:02:23

TypeScript根本不做任何运行时类型检查。类型检查在编译时进行,类型信息不包括在生成的JavaScript文件中。

post.ts

代码语言:javascript
复制
type ValidLetter = "A" | "B" | "C";

function post(letter: ValidLetter) {
}

生成以下JavaScript:

post.js

代码语言:javascript
复制
function post(letter) {
}

因此,您必须在运行时代码中手动重新指定类型检查:

代码语言:javascript
复制
type ValidLetter = "A" | "B" | "C";

function post(letter: ValidLetter) {
  if (letter !== "A" && letter !== "B" && letter !== "C") throw "error!";
}

不算太坏。但这有点多余,不是吗?

有一个名为runtypes的库,它允许您指定类型一次,它会生成一个编译时TypeScript类型,并保留类型信息以进行运行时检查:

代码语言:javascript
复制
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);
}

因此,现在您可以获得完整的编译时检查和运行时检查。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45068893

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档