简体   繁体   English

Typescript - 使用字符串获取名称的属性,作为泛型类型

[英]Typescript - Get property of name with string, as generic type

I butchered the title, not sure the technical term for what I want to do.我扼杀了标题,不确定我想做的事情的技术术语。 Type constraints are a bit mind boggling to me at the moment as I learn them in both F# and Typescript simultaneously.当我同时在 F# 和 Typescript 中学习它们时,类型约束对我来说有点令人难以置信。

I have a variable of interface state that holds lists of every type of data needed on the page我有一个接口状态变量,它包含页面上所需的每种类型数据的列表

interface state{
    clients: clients[]
    appointments: appointments[]
    ...
}

const ApplicationState : state = {...}

I want a generic function that can be used to get a specific client, appointment, whatever by id.我想要一个通用函数,可用于通过 id 获取特定客户、约会。

So something that looks like所以看起来像

getData('clients', 2)

I have started by defining a type of allowed properties (if this can be done a better way let me know).我首先定义了一种允许的属性(如果有更好的方法让我知道)。

type entity = "clients" | "appointments"

But would I then be able to get the property of ApplicationState ?但是我能得到ApplicationState的属性吗?

So the getData function could look something like this?那么getData函数可能看起来像这样吗?

const getData = (foo: entity, id: number) => {
    ApplicationState.magicallyGetPropertyByName.filter(entity => entity.id = foo.id)
}

Is this possible while keeping type inference?在保持类型推断的同时这可能吗?

Thank you谢谢

The main problem here, is that you are not allowed to call filter on a union like this:这里的主要问题是你不能像这样在联合上调filter


type Clients = {
  tag: 'Clients'
  id: number
}

type Appointments = {
  tag: 'Appointments'
  id: number
}

declare const test: Clients[] | Appointments[]

test.filter(elem => elem)

Please see issues/7294 and issues/13097请参阅问题/7294问题/13097

However, there is a workaround:但是,有一个解决方法:

type Clients = {
  tag: 'Clients'
  id: number
}

type Appointments = {
  tag: 'Appointments'
  id: number
}

type State = {
  clients: Clients[]
  appointments: Appointments[]
}

type Entity = keyof State;

declare const ApplicationState: State

const withState = <
  S extends Record<string, { id: number }[]>
>(state: S) =>
  <E extends keyof S>(prop: E, id: number) =>
    state[prop].filter(entity => entity.id === id)

const getData = withState(ApplicationState);

getData('clients', 2)

Playground As you might have noticed, I have declared State as a type instead of interface . Playground您可能已经注意到,我已经将State声明为一种type而不是interface This is because interfaces are not indexed by the default.这是因为默认情况下interfaces未编入索引。 If you change it back to interface , withState will cause an error.如果将其改回interfacewithState将导致错误。

In fact, you don't need to know exact types of clients and appointments , you just have to make sure that all of these types have common property id .事实上,您不需要知道clientsappointments确切类型,您只需要确保所有这些类型都具有公共属性id

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

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