简体   繁体   English

如何使用枚举从 TypeScript 中的导入中确定要使用的项目?

[英]How to use enum to determine which item to use from an import in TypeScript?

Overview概述

We have a module that exports objects from other files.我们有一个从其他文件导出对象的模块。

For simplicity sake, let's call this Vehicle .为简单起见,我们称它为Vehicle It exports Car , Boat , and Plane .它出口CarBoatPlane

We have an enum that corresponds to these vehicles, let's say the following:我们有一个对应于这些车辆的枚举,假设如下:

enum Vehicles {
    Car,
    Boat,
    Plane,
}

We are looking to use the enum to specify which imported object we should then use.我们希望使用枚举来指定我们应该使用哪个导入的 object。


Question问题

We're aware that we can do a switch/case, but this becomes unnecessarily long as our enum grows.我们知道我们可以做一个开关/案例,但是随着我们的枚举增长,这变得不必要了。 Some of our classes export dozens of variations of objects that we then use elsewhere (we are unable to use types/interfaces to simplify).我们的一些类导出了几十个对象的变体,然后我们在其他地方使用(我们无法使用类型/接口来简化)。

switch(vehicle) {
    case Vehicles.Car: {
        return Car;
    }
    case Vehicles.Boat: {
        return Boat;
    }
    case Vehicles.Plane: {
        return Plane;
    }
}

More info更多信息

We are using TypeScript with Svelte.我们将 TypeScript 与 Svelte 一起使用。 The import is a package (eg Google Charts [charts], fortawesome [icons], etc.).导入的是 package(例如 Google Charts [charts]、fortawesome [icons] 等)。 We are looking to create a sort of wrapper to easily initialize specific components.我们正在寻求创建一种包装器来轻松初始化特定组件。

Example:例子:

<script lang="ts">
    import { a, b, c } from x
    const y = () => {
        // logic here
    }
</script>

<y/>

This question seems to be TypeScript-specific, so I've purposely left out svelte tag from my question这个问题似乎是特定于 TypeScript 的,所以我故意在我的问题中省略了 svelte 标签

So I tried some things, here you can see them:所以我尝试了一些东西,在这里你可以看到它们:


What I originally wanted to do我原本想做的事

I tried to assign the classes to the enum properties, but it didn't work.我试图将类分配给枚举属性,但它不起作用。 How I imagined it is like this:我如何想象它是这样的:

enum Vehicle {
    Car = Car,
    Boat = Boat,
    Plane = Plane,
}

But TypeScript gives me an error.但是 TypeScript 给了我一个错误。 You can try it here .你可以在这里试试。 Why did I think about that?为什么我会这么想? Because you can assign value to enum properties like this:因为您可以像这样为枚举属性赋值:

enum Char {
    A = 65,
    B = 66,
    C = 67,
    D = 68,
    // ...
}

But as you can see, it doesn't work in your case.但正如您所看到的,它不适用于您的情况。


A possible solution一个可能的解决方案

You could just forget using an enum.你可能会忘记使用枚举。 There is a special feature in TypeScript, as const . TypeScript 中有一个特殊功能, as const It makes an array or object literal constant.它使数组或 object 文字常量。 That would look somehow like this:这看起来像这样:

const Vehicle = {
    Car,
    Boat,
    Plane
} as const;

Why don't I use a value?为什么我不使用值? That is called property shorting (or something like that).这称为属性短路(或类似的东西)。 When you have a variable or some named thing and want to use it with the same property name, you don't have to specify one.当你有一个变量或一些命名的东西并想用相同的属性名称使用它时,你不必指定一个。 Here is the example using the as const version. 是使用as const版本的示例。


What when you want to get the class by an index? 当您想通过索引获取 class 时怎么办?

You can use Object.keys to get an array of keys.您可以使用Object.keys获取密钥数组。 It look somehow like this:它看起来像这样:

 const index = 1; const keys = Object.keys(Vehicle); const vehicle = Vehicle[keys[index]];

I'm not going to add a link here because it is not really important.我不会在这里添加链接,因为它并不重要。

You can use a map of您可以使用 map

const vehicleComponentsMap: Record<Vehice, SvelteComponent> = {
   [Vehicle.Car]: Car,
   ....
}

And then if you have a convention for the Vehicle implementation files, you can use it to dynamically build this map (by collecting data from files by convention).然后,如果您有 Vehicle 实现文件的约定,则可以使用它来动态构建此 map(通过按约定从文件中收集数据)。

My solution is largely inspired by blaumeise20.我的解决方案很大程度上受到了 blaumeise20 的启发。

Note: React is just used as an example here.注意:这里仅以 React 为例。 Your imports can be anything你的进口可以是任何东西

Heres what I came up with:这是我想出的:

import { Component, useCallback, useEffect } from 'react';

const imports = { Component, useCallback, useEffect } as const;

function getCorrectImport<K extends keyof typeof imports>(key: K): typeof imports[K] {
  return imports[key];
}

You can then call this function like this:然后你可以像这样调用这个 function:

getCorrectImport('Component'); // You should get completion hints and correct typings using this

The Downside is you will need to stuff your imports into an object like I created the imports object.不利的一面是,您需要将导入的内容填充到object中,就像我创建了imports object 一样。

A cool way if you import everything from a module could be something like this:如果您从模块中导入所有内容,一个很酷的方法可能是这样的:

import * as React from 'react';

function getCorrectImport<K extends keyof typeof React>(key: K): typeof React[K] {
  return React[key];
}

const correctObject = getCorrectImport('Component');

This can allow you to not create an object but the downside would be you would need to import everything from the module you are importing from.这可以让您不创建 object,但缺点是您需要从要导入的模块中导入所有内容。 This works because the * as React syntax creates an object for you.这是有效的,因为* as React语法为您创建了 object。

If you can do that, this would be an ideal solution.如果你能做到这一点,这将是一个理想的解决方案。

Playground link 游乐场链接

Why can't you use this one?为什么不能用这个?

enum Vehicle {
Car= 'CAR',
Boat= 'BOAT',
Plane= 'PLANE',

} }

Regards, N Baua问候, N Baua

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM