如何在 TypeScript 界面中请求特定字符串

问题描述 投票:0回答:10

我正在为第 3 方 js 库创建 TypeScript 定义文件。其中一种方法允许使用选项对象,并且选项对象的属性之一接受列表中的字符串:

"collapse"
"expand"
"end-expand"
"none"

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

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

接口是否可以强制执行此操作,因此,如果您包含具有

IOptions
属性的
brace_style
对象,它将只允许可接受列表中的字符串?

typescript
10个回答
452
投票

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

Typescript 中的新增功能 - 字符串文字类型

页面示例:

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

355
投票

试试这个

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

export interface IReadings {
   param:ReadingTypes
}

编辑:非常感谢您的支持,但是,随着时间的推移和我作为开发人员的发展:),现在在大多数情况下我不会再推荐这种方法。是的,它仍然有效,但重点是上面的构造与枚举结构非常相似,所以为什么不使用枚举来代替(优点如下):

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

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

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

在第一种情况下,当您阅读代码时,乍一看您无法捕捉到该 .reading 字段只能包含少数某些参数,而不是任何字符串值。

  1. 当您编写代码时,如果您使用枚举,您将获得编辑器的更好帮助 - 记住枚举的名称并编写它就足够了,它会向您显示枚举的所有变体。是的,对于第一种类型('some' | 'variants' ...)它也可以这样做,但它做得更少......嗯..急切

26
投票

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'};

15
投票

在 TypeScript 2.4 及以上版本中,您可以使用 String Enums

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

可以创建一个值为字符串的枚举

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

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

export interface UserOptions  {
  visibility:  VISIBILITY 
}

10
投票

也许不完全是您想要的,但

Enum
似乎是您的完美解决方案。

enum BraceStyle {Collapse, Expand, EndExpand, None}

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

但是,枚举是基于数字的。这意味着在运行时,例如的实际值在这种情况下,

BraceStyle.Collapse
将为 0。但是您可以将它们与其他脚本一起使用,甚至是非打字稿脚本,因为它们编译为对象。这就是
BraceStyle
编译和运行后的样子:

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

如果您想要字符串,则可以使用具有静态成员的类,如此处

所述

2
投票
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

1
投票

enum
可能是最好的解决方案,但是如果您将值作为 const 对象的键并且无法更改它,则语法将是

brace_style?: typeof BRACE_STYLES[keyof typeof BRACE_STYLES];

其中

BRACE_STYLES
是 const 对象的名称


1
投票

您很可能需要

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
存在,而不需要对类型进行硬编码。


0
投票

您可以按照其他人的说明创建自定义类型。
我想补充一点,您还可以从对象 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.member 类型

对象与枚举


0
投票

这个答案有点宽泛,但可以扩展到许多用例。 您会利用

MappedTypes

这是一个用例:


// Let's say that you have different string literals defining a 'type' property
// i.e: 'text' | 'video' | 'image' […]
// You would like each 'type' to 'enable' or 'disable' different   
// properties based on the `type` property:
const fooObj: MyObject = {
    type: "foo",
    value: {
        sharedProp: "shared",
        fooProperty1: 123,
        fooProperty2: "hello"
    }
};

const barObj: MyObject = {
    type: "bar",
    value: {
        sharedProp: "shared",
        barProperty1: true,
        barProperty2: new Date()
    }
};



type CommonProps = {
    sharedProp: "shared";
};

type FooProperties = {
    fooProperty1: number;
    fooProperty2: string;
    // ... other foo properties
};

type BarProperties = {
    barProperty1: boolean;
    barProperty2: Date;
    // ... other bar properties
};

type AllProperties = {
    foo: FooProperties,
    bar: BarProperties,
    // ... other discriminators and their properties
};

type MyObject = {
    [K in keyof AllProperties]: {
        type: K;
        value: AllProperties[K] & CommonProps;
    };
}[keyof AllProperties];


© www.soinside.com 2019 - 2024. All rights reserved.