英文:
Typescript template literal mapped type
问题
以下是您要翻译的代码部分:
我正在开发一个转换器应用程序,一直在尝试着使用模板文字作为映射类型的对象类型。
我想要做的是:在下面的代码中对`formulas`对象进行类型定义,该对象将包含将摄氏度转换为开尔文、开尔文转换为华氏度等的所有公式。
我能够像这样对其进行类型定义:
```typescript
type ConversionsOptions<T extends TemperatureUnit> = {
  key: ConversionCategoryType;
  items: Array<ConversionItem<T>>;
  formulas: {
    [U in `${T}_to_${T}`]: (n: number) => number;
  };
};
用于转换的对象看起来是这样的:
const temperatureCategory: ConversionsOptions<
  'celsius' | 'farenheit' | 'kelvin'
> = {
  key: 'temperature',
  items: [
    {
      key: 'celsius',
    },
    {
      key: 'kelvin',
    },
    {
      key: 'farenheit',
    },
  ],
  formulas: {
    celsius_to_kelvin: (n: number) => n + 273.15,
    celsius_to_farenheit: (n: number) => n * (9 / 5) + 32,
    kelvin_to_farenheit: (n: number) => (n - 273.15) * (9 / 5) + 32,
    kelvin_to_celsius: (n: number) => n - 273.15,
    farenheit_to_kelvin: (n: number) => (n - 32) * (5 / 9) + 273.15,
    farenheit_to_celsius: (n: number) => (n - 32) * (5 / 9),
  },
};
因此,使用这种类型,公式对象的索引是正确的,但允许celsius_to_celsius、farenheit_to_farenheit和kelvin_to_kelvin出现在对象中。
我尝试使用排除(Exclude)实用程序类型,如下所示:
[U in `${T}_to_${Exclude<T, U>}`]: (n: number) => number;
在映射类型中,但不幸的是,它不起作用。
有没有什么想法可以解决这个问题?
<details>
<summary>英文:</summary>
i'm working on a converter app and have been trying ~ for a while now ~ to successfuly type an object with template literals as a mapped type.
What I want to do: type the `formulas` object in the code below, that would contain every formula to convert celsius to kelvin, kelvin to farenheit, etc.
I was able to type it like that :
```typescript
type ConversionsOptions<T extends TemperatureUnit> = {
  key: ConversionCategoryType;
  items: Array<ConversionItem<T>>;
  formulas: {
    [U in `${T}_to_${T}`]: (n: number) => number;
  };
};
The object for the conversions looks like that :
const temperatureCategory: ConversionsOptions<
  'celsius' | 'farenheit' | 'kelvin'
> = {
  key: 'temperature',
  items: [
    {
      key: 'celsius',
    },
    {
      key: 'kelvin',
    },
    {
      key: 'farenheit',
    },
  ],
  formulas: {
    celsius_to_kelvin: (n: number) => n + 273.15,
    celsius_to_farenheit: (n: number) => n * (9 / 5) + 32,
    kelvin_to_farenheit: (n: number) => (n - 273.15) * (9 / 5) + 32,
    kelvin_to_celsius: (n: number) => n - 273.15,
    farenheit_to_kelvin: (n: number) => (n - 32) * (5 / 9) + 273.15,
    farenheit_to_celsius: (n: number) => (n - 32) * (5 / 9),
  },
};
So with this type, the formula's object indexes are correct but it allows celsius_to_celsius, farenheit_to_farenheit and kelvin_to_kelvin to be in the object.
I tried to use Exclude utility type like this :
[U in `${T}_to_${Exclude<T, U>}`]: (n: number) => number;
in the mapped type, but unfortunately, it doesn't work.
Any ideas how this problem could be solved ?
答案1
得分: 2
If we use key remapping, we can use Exclude:
type ConversionsOptions<T extends TemperatureUnit> = {
  formulas: {
    [U in T as `${U}_to_${Exclude<T, U>}`]: (n: number) => number;
  };
};
We can make a type that gets the duplicates utilizing distributive conditional types:
type Duplicates<T extends string> = T extends T ? `${T}_to_${T}` : never;
and then simply omit the dupes from the mapped type:
type ConversionsOptions<T extends TemperatureUnit> = {
  formulas: Omit<{
    [U in `${T}_to_${T}`]: (n: number) => number;
  }, Duplicates<T>>;
};
You could also inline the type if you don't want to create another type that's only used once:
type ConversionsOptions<T extends TemperatureUnit> = {
  formulas: Omit<{
    [U in `${T}_to_${T}`]: (n: number) => number;
  }, T extends T ? `${T}_to_${T}` : never>;
};
英文:
If we use key remapping, we can use Exclude:
type ConversionsOptions<T extends TemperatureUnit> = {
  formulas:{
    [U in T as `${U}_to_${Exclude<T, U>}`]: (n: number) => number;
  };
};
We can make a type that gets the duplicates utilizing distributive conditional types:
type Duplicates<T extends string> = T extends T ? `${T}_to_${T}` : never;
and then simply omit the dupes from the mapped type:
type ConversionsOptions<T extends TemperatureUnit> = {
  formulas: Omit<{
    [U in `${T}_to_${T}`]: (n: number) => number;
  }, Duplicates<T>>;
};
You could also inline the type if you don't want to create another type that's only used once:
type ConversionsOptions<T extends TemperatureUnit> = {
  formulas: Omit<{
    [U in `${T}_to_${T}`]: (n: number) => number;
  }, T extends T ? `${T}_to_${T}` : never>;
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论