简体   繁体   English

将字符串映射到 TypeScript 中的模板文字类型

[英]Mapping a string to Template Literal Type in TypeScript

Is there a way to map a string to a matching template literal type in TypeScript?有没有办法将字符串映射到 TypeScript 中匹配的模板文字类型?

Here's an example:下面是一个例子:

type SomeType<T> = {
  [P in keyof T as `as${Capitalize<string & P>}`]: number;
};

This should take every property x of T and make it into a property asX .这应该采用T每个属性x并将其转换为属性asX

But now I'd like to take a property name like foo and convert it into asFoo in a way that TypeScript can detect.但是现在我想采用像foo这样的属性名称,并以 TypeScript 可以检测到的方式将其转换为asFoo

I'd like to be able to do this:我希望能够做到这一点:

interface I {
  foo: number;
  bar: number;
}

const obj: SomeType<I> = {
  asFoo: 1,
  asBar: 2,
};

const str = 'foo';
// Doesn't work, trying to capitalize str, but TypeScript only sees it as a string
obj[`as${str[0].toUpperCase()}${str.slice(1)}`];

I'd like to somehow take str and index obj .我想以某种方式采用str和索引obj Is this possible somehow?这有可能吗? I suppose I could cast the string but I'd rather not do that.我想我可以投射字符串,但我宁愿不这样做。

Currently I'm handling this by creating a function like this:目前我正在通过创建这样的函数来处理这个问题:

function getProperty(key: string): keyof SomeType<I> {
  return key === 'foo' ? 'asFoo' : 'asBar';
}

obj[getProperty('foo')];

But I just want to see if there is a more elegant solution as this can get out of hand if there are a lot of properties.但我只想看看是否有更优雅的解决方案,因为如果有很多属性,这可能会失控。 I'm pretty new to TypeScript so I may be missing something.我对 TypeScript 还很陌生,所以我可能会遗漏一些东西。

I usually try to split my logic into smallest possible parts.我通常尝试将我的逻辑分成尽可能小的部分。 COnsider this example:考虑这个例子:

type SomeType<T> = {
    [P in keyof T as `as${Capitalize<string & P>}`]: number;
};

interface Obj {
    foo: number;
    bar: number;
}

const obj: SomeType<Obj> = {
    asFoo: 1,
    asBar: 2,
};


const capitalize = <Key extends string>(key: Key) =>
    `${key[0].toUpperCase()}${key.slice(1)}` as Capitalize<Key>

const withPrefix = <Key extends string>(key: Key): `as${Key}` => `as${key}`

const getProperty = <Key extends string>(key: Key) => withPrefix(capitalize(key))


const result = getProperty('foo') // asFoo

const getter = obj[result] // number

Playground 操场

This line as${Capitalize<string & P>} consists of two actions:这行as${Capitalize<string & P>}包含两个操作:

  1. capitalization,大写,

  2. adding as prefix添加as前缀

this is why I have used two functions for it这就是为什么我使用了两个函数

As you might have noticed, withPrefix and getProperty might be composed:您可能已经注意到, withPrefixgetProperty可能由以下组成:

import { compose } from 'redux'


const capitalize = <Key extends string>(key: Key) =>
    `${key[0].toUpperCase()}${key.slice(1)}` as Capitalize<Key>

const withPrefix = <Key extends string>(key: Key): `as${Key}` => `as${key}`

type Fn =
    <Key extends string>(key: Key) => `as${Capitalize<Key>}`

const getProperty =
    compose(withPrefix, capitalize) as Fn

const result = getProperty('foo') // asFoo

but it requires you to use extra compose functions with type assertions.但它要求您使用带有类型断言的额外compose函数。

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

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