首页 > 解决方案 > 从字符串动态创建字符串文字类型

问题描述

有没有办法从字符串动态创建字符串文字类型,而不是从字符串中创建一个数组,然后使用 typeof 提取其类型,如this answer所示?

const url = 'text'
const URL = [url]
type P = (typeof URL)[number];

编辑我想要实现的是构建,一种基于给定字符串(端点 URL)的方法将能够提取我需要提供的端点参数所需的内容。

export type ExtractRouteParams<T> = string extends T
? Record<string, string>
: T extends `${infer _Start}:${infer Param}/${infer Rest}`
? { [k in Param | keyof ExtractRouteParams<Rest>]: string }
: T extends `${infer _Start}:${infer Param}`
? { [k in Param]: string }
: {};

ExtractRouteParams 是一种基于给定字符串返回我的类型的类型,该类型定义了需要什么样的参数。当我这样使用它时,它工作得很好。

type Test = ExtractRouteParams<'actions/:actionId/test/:testId'>

但我希望它更动态地工作。我创建了一个工厂 URL 方法,我想在其中基于作为参数提供的 URL 创建类型。该方法返回泛型类(基于该动态类型),其中包含创建 url 的方法。

export function urlFactory(url: string) {
  type P = typeof url;
  return new InterpolateUrl<P>();
}

class InterpolateUrl<T extends string> {
  url(params: ExtractRouteParams<T>): void {

  }
}

const endpoints = {
    endpoint: urlFactory(
       'actions/:actionId/test/:testId'
    )
};

不幸的是 InterpolateUrl 类方法url没有正确指向所需的params。相比之下,类型 Test 确实如此。

这里游乐场

标签: typescript

解决方案


更新

鉴于您更新的问题和示例,看起来您想要的只是让您的urlFactory()函数本身是generic。编译器并不会真正查看特定类型string并对其进行通用处理,因为输出类型对您来说会更好;当你需要泛型时,你必须告诉编译器:

export function urlFactory<P extends string>(url: P) {
  return new InterpolateUrl<P>();
}

一旦你这样做,事情就会如愿以偿,我认为:

console.log(endpoints.endpoint.url({
  actionId: "hey",
  testId: "you"
})); // okay

console.log(endpoints.endpoint.url({
  // error!
  // Type '{}' is missing the following properties from type 
  // '{ actionId: string; testId: string; }': actionId, testId
}))

Playground 代码链接


原始答案

您可以直接使用TypeScripttypeof类型查询运算符url,而无需创建中间数组:

const url = 'text'
type P = typeof url;
// type P = "text"

Playground 代码链接


推荐阅读