如何要求一个特定的字符串在TypeScript接口

我正在为第三方js库创建一个TypeScript定义文件。其中一个方法允许使用options对象,而options对象的一个属性接受列表中的字符串:"collapse""expand""end-expand""none"

我有一个接口的选项对象:

interface IOptions {
indent_size?: number;
indent_char?: string;
brace_style?: // "collapse" | "expand" | "end-expand" | "none"
}

接口是否可以强制执行这一点,因此如果包含带有brace_style属性的IOptions对象,它将只允许可接受列表中的字符串?

191132 次浏览

也许不是你想要的,但Enums似乎是一个完美的解决方案。

enum BraceStyle {Collapse, Expand, EndExpand, None}


interface IOptions {
indent_size?: number;
indent_char?: string;
brace_style?: BraceStyle
}

然而,枚举是基于数字的。这意味着在运行时,例如BraceStyle.Collapse的实值在这种情况下将为0。但是您可以将它们用于其他脚本,甚至是非typescript脚本,因为它们被编译为对象。这是BraceStyle在compile&run之后的样子:

{
0: "Collapse",
1: "Expand",
2: "EndExpand",
3: "None",
Collapse: 0,
Expand: 1,
EndExpand: 2,
None: 3
}

如果你想要字符串,你可以使用带有静态成员的类,如在这里所述

这在1.8版本中作为“字符串文字类型”发布

. Typescript新增功能- String Literal Types .

本页示例:

interface AnimationOptions {
deltaX: number;
deltaY: number;
easing: "ease-in" | "ease-out" | "ease-in-out";
}

试试这个

export type ReadingTypes = 'some'|'variants'|'of'|'strings';


export interface IReadings {
param:ReadingTypes
}

编辑:非常感谢你的支持,但是随着时间的推移,我也逐渐成长为一名开发者:),现在在大多数情况下,我不会再推荐这种方法了。是的,它仍然有效,但重点是上面的结构非常类似于enum结构,所以为什么不使用enum代替(优点如下):

export enum ReadingTypes {
Some = 'some',
Variants = 'variants',
Of = 'of',
Strings = 'strings',
}
export interface IReadings {
param: ReadingTypes
}

优点:(是的,可能它更像IMHO,我理解,但是,尽管如此)

  1. 例如,当您在代码中看到它时,它更具有可读性
if(item.reading === 'some') {
...
}
// vs
if(item.reading === ReadingTypes.Some) {
...
}

在第一种情况下,当您阅读代码时,乍一看,.reading字段只能包含一些特定的参数,而不是任何字符串值。

  1. 当你写代码时,如果你使用枚举,你的编辑器会有更好的帮助——记住enum的名字就足够了,它会告诉你enum的所有变体。是的,用第一种类型('一些' | '变体'…)它也可以这样做,但它做得较少。嗯. .急切地
function keysOf<T>(obj: T, key: keyof T) { return obj[key]; }
interface SomeInterface {
a: string;
}
const instance: SomeInterface = { a: 'some value'};
let value = keysOf<SomeInterface>(instance, 'b'); // invalid
value =  keysOf<SomeInterface>(instance, 'a'); // valid

TS提供了对特定字符串值的类型,称为字符串文字类型

下面是一个如何使用它们的例子:

type style =  "collapse" | "expand" | "end-expand" | "none";


interface IOptions {
indent_size?: number;
indent_char?: string;
brace_style1?:  "collapse" | "expand" | "end-expand" | "none";
brace_style2?:  style;
}


// Ok
let obj1: IOptions = {brace_style1: 'collapse'};


// Compile time error:
// Type '"collapsessss"' is not assignable to type '"collapse" | "expand" | "end-expand" | "none" | undefined'.
let obj2: IOptions = {brace_style1: 'collapsessss'};

在TypeScript 2.4以后,你可以使用字符串枚举

我喜欢这种方法,因为它避免了在多个地方使用相同的硬编码字符串的需要。

可以创建一个枚举,其中值为字符串

export enum VISIBILITY {
PUBLISH = "publish",
DRAFT = "draft"
}

这个枚举可以用作接口或类上的类型

export interface UserOptions  {
visibility:  VISIBILITY
}

enum可能是最好的解决方案,但如果你把你的值作为一个const对象的键,你不能改变它,语法将是

brace_style?: typeof BRACE_STYLES[keyof typeof BRACE_STYLES];

其中BRACE_STYLES是const对象的名称

您可以根据其他人的说明创建自定义类型。
我还要补充一点,你也可以从对象const推断创建的类型:

export const braceStyles = {
collapse: "collapse",
expand: "expand",
end-expand: "end-expand",
none: "none"
}


export type braceStyle = typeof braceStyles[keyof typeof braceStyles]


export interface IOptions {
indent_size?: number;
indent_char?: string;
brace_style?: bracestyle;
}

这样你就不必使用enum,你也可以在任何需要它们的地方使用对象属性,在那里它们的类型将是string,而不是enum.member

对象vs枚举

你很可能需要enum选项。但如果你没有,你真的需要你的const存在,这里一些回答帖子的keyOf可以工作,只做了轻微修改:

export const BRACE_STYLES = {
collapse: 'collapse',
'end-expand': 'end-expand',
expand: 'expand',
none: 'none'
}


export type BraceStyle = keyof typeof BRACE_STYLES


export interface IOptions {
indent_size?: number
indent_char?: string
brace_style?: BraceStyle
}

这实际上会得到你想要的"collapse" | "expand" | "end-expand" | "none"效果,仍然允许const存在,而不需要对类型进行硬编码。