[英]Typescript: Simplify typing of enum-like objects
in JavaScript I often (ab)use objects as pseudo-enums :在 JavaScript 中,我经常(ab)使用对象作为伪枚举:
const application = {
ELECTRIC: {propA: true, propB: 11, propC: "eee"},
HYDRAULIC: {propA: false, propB: 59, propC: "hhh"},
PNEUMATIC: {propA: true, propB: 87, propC: "ppp"},
}
const foo = application.ELECTRIC
const bar = application.HYDRAULIC
I'd like to achieve a similar behavior in TypeScript, but in a type-safe manner.我想在 TypeScript 中实现类似的行为,但以类型安全的方式。 Here's what I have so far:
这是我到目前为止所拥有的:
type Application = "ELECTRIC" | "HYDRAULIC" | "PNEUMATIC";
interface ApplicationProps {
propA: boolean;
propB: number;
propC: string;
}
const application: Record<Application, ApplicationProps> = {
ELECTRIC: {propA: true, propB: 11, propC: "eee"},
HYDRAULIC: {propA: false, propB: 59, propC: "hhh"},
PNEUMATIC: {propA: true, propB: 87, propC: "ppp"},
}
const foo = application.ELECTRIC;
---
let bar: ApplicationProps; // an attempt to restrict bar to application.ELECTRIC|application.HYDRAULIC|application.PNEUMATIC
bar = application.HYDRAULIC;
That works okay but feels clumsy.这行得通,但感觉很笨拙。
1) There seems to be lot of repetition in type/interface/object 1)类型/接口/对象似乎有很多重复
Is there some TS-Trickery to automatically infer type Application
/ interface ApplicationProps
from the object?是否有一些 TS-Trickery 可以从对象自动推断
type Application
/ interface ApplicationProps
? Like some keyof typeof something
magic?像一些
keyof typeof something
?
2) It feels strange to type bar
as ApplicationProps
when I actually want to restrict it to members of application
2)当我实际上想将它限制为
application
成员时,将bar
键入为ApplicationProps
感觉很奇怪
Is there a more elegant way to restrict bar
to application.ELECTRIC|application.HYDRAULIC|...
?有没有更优雅的方式将
bar
限制为application.ELECTRIC|application.HYDRAULIC|...
?
3) If I want to define bar
in another file, I need to import ApplicationProps
and application
. 3)如果我想在另一个文件中定义
bar
,我需要导入ApplicationProps
和application
。 I know the type info is part of application
but I don't know how to get it.我知道类型信息是
application
的一部分,但我不知道如何获取它。
The best I got so far was: let bar: typeof application[keyof typeof application]
Which of course is stupid.到目前为止我得到的最好的是:
let bar: typeof application[keyof typeof application]
这当然是愚蠢的。 There has to be a better way?!一定有更好的方法?!
So you can do something like this:所以你可以做这样的事情:
// all application keys will be defined here
// as const is needed here so typescript won't start widening the type to string[]
const applications = ["ELECTRIC", "HYDRAULIC", "PNEUMATIC"] as const
// get all keys as a Union Type
type ApplicationKeys = typeof applications[number]
// create your enum object as a type
type Application = { [Key in ApplicationKeys]: ApplicationProps<Key> }
// define your props with a key so typescript can differentiate between your enums
type ApplicationProps<T> = {
key: T,
propA: boolean;
propB: number;
propC: string;
}
// the actual enum definition
const application: Application = {
ELECTRIC: { key: "ELECTRIC", propA: true, propB: 11, propC: "eee" },
HYDRAULIC: { key: "HYDRAULIC", propA: false, propB: 59, propC: "hhh" },
PNEUMATIC: { key: "PNEUMATIC", propA: true, propB: 87, propC: "ppp" },
}
// test
let foo = application.ELECTRIC;
let bar: Application["PNEUMATIC"];
bar = application.HYDRAULIC; // error: Type 'ApplicationProps<"HYDRAULIC">' is not assignable to type 'ApplicationProps<"ELECTRIC">'.
bar ===foo // error his condition will always return 'false' since the types have no overlap
The neat part is that if you want to add a new application key you just have to add it to the list and typescript will throw errors for the missing or unhandled key in a switch or if statement(exhaustive switch block)[https://stackoverflow.com/questions/39419170/how-do-i-check-that-a-switch-block-is-exhaustive-in-typescript].巧妙的部分是,如果您想添加一个新的应用程序密钥,您只需将其添加到列表中,打字稿将针对 switch 或 if 语句中丢失或未处理的密钥引发错误(详尽的 switch 块)[https:// stackoverflow.com/questions/39419170/how-do-i-check-that-a-switch-block-is-exhaustive-in-typescript]。
I hope you understand my bad english :) CODE我希望你能理解我糟糕的英语:) 代码
I sometimes do something like this, with having a enum list mapping to specific types.我有时会做这样的事情,将枚举列表映射到特定类型。
But I'm also curious about how this could be done better.但我也很好奇如何才能做得更好。
enum ApplicationType {
ELECTRIC = 'ELECTRIC',
HYDRAULIC = 'HYDRAULIC',
PNEUMATIC = 'PNEUMATIC',
}
interface Application {
propA: boolean;
propB: number;
propC: string;
}
interface ElectricApplication extends Application {
propD: string;
}
interface PneumaticApplication extends Application {}
interface HydaulicApplication extends Application {}
type ApplicationTypeMap = {
[ApplicationType.ELECTRIC]: ElectricApplication;
[ApplicationType.HYDRAULIC]: HydaulicApplication;
[ApplicationType.PNEUMATIC]: PneumaticApplication;
};
const applications: { [key in ApplicationType]: ApplicationTypeMap[key] } = {
ELECTRIC: {
propA: true,
propB: 11,
propC: 'eee',
propD: 'boo',
},
HYDRAULIC: { propA: false, propB: 59, propC: 'hhh' },
PNEUMATIC: { propA: true, propB: 87, propC: 'ppp' },
};
const foo = applications[ApplicationType.ELECTRIC];
console.log(foo.propD);
const bar = applications[ApplicationType.HYDRAULIC];
console.log(bar.propA);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.