我正在为第 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
对象,它将只允许可接受列表中的字符串?
这在 1.8 版本中作为“字符串文字类型”发布
页面示例:
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
}
编辑:非常感谢您的支持,但是,随着时间的推移和我作为开发人员的发展:),现在在大多数情况下我不会再推荐这种方法。是的,它仍然有效,但重点是上面的构造与枚举结构非常相似,所以为什么不使用枚举来代替(优点如下):
export enum ReadingTypes {
Some = 'some',
Variants = 'variants',
Of = 'of',
Strings = 'strings',
}
export interface IReadings {
param: ReadingTypes
}
优点:(是的,可能它更像是恕我直言,我理解,但是,尽管如此)
if(item.reading === 'some') {
...
}
// vs
if(item.reading === ReadingTypes.Some) {
...
}
在第一种情况下,当您阅读代码时,乍一看您无法捕捉到该 .reading 字段只能包含少数某些参数,而不是任何字符串值。
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'};
我喜欢这种方法,因为它避免了在多个地方使用相同的硬编码字符串的需要。
可以创建一个值为字符串的枚举
export enum VISIBILITY {
PUBLISH = "publish",
DRAFT = "draft"
}
这个枚举可以用作接口或类上的类型
export interface UserOptions {
visibility: VISIBILITY
}
也许不完全是您想要的,但
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
}
如果您想要字符串,则可以使用具有静态成员的类,如此处
所述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
enum
可能是最好的解决方案,但是如果您将值作为 const 对象的键并且无法更改它,则语法将是
brace_style?: typeof BRACE_STYLES[keyof typeof BRACE_STYLES];
其中
BRACE_STYLES
是 const 对象的名称
您很可能需要
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
存在,而不需要对类型进行硬编码。
您可以按照其他人的说明创建自定义类型。
我想补充一点,您还可以从对象 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 类型
这个答案有点宽泛,但可以扩展到许多用例。 您会利用
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];