简体   繁体   中英

Typescript dynamic object return type based on array parameter

With the following abstraction, I am able to call this method and the return type is based on the string based fields I pass into it shown below.

abstract class Entity {
  abstract id: string
}

class User extends Entity {
  constructor(obj: Partial<User>) {
    super()
    Object.assign(this, obj)
  }

  id: string
  name: string
  age: number
}

class Post extends Entity {
  constructor(obj: Partial<Post>) {
    super()
    Object.assign(this, obj)
  }

  id: string
  content: string
  time: Date
}


export const useSyncFields = <T extends Entity, U extends (keyof T & string)[]>(
  type: { new(obj: T): T },
  id: string,
  fields: U,
): { [K in U[number]]: T[K] } => {
   ...
}

const user1: {id: string, name: string} = useSyncFields(User, "1234", ["id", "name"])
const user2: {id: string, age: number} = useSyncFields(User, "1234", ["id", "age"])
const post: {content: string} = useSyncField(Post, "4567", ["content"]
// etc

By using the type params <T extends Entity, U extends (keyof T & string)[] and the return type { [K in U[number]]: T[K] } , the inferred return type from Typescript "correct", but neither VSCode or WebStorm do an awesome job inferring the type correctly.

I feel like there's a better set of type params / return types that would be better inferred. Is what I have really the best I could be doing here? Or is there some type ninja out there who can guide me to a better solution?

If you simply want to make this simpler, I'd go with:

export const useSyncFields = <T extends Entity, U extends keyof T>(
  type: { new(obj: T): T },
  id: string,
  fields: U[],
): Pick<T, U> => {
   return {} as any // implementation
}

If you don't care about the length or order of arrays in your type then you don't need be generic over the whole array. So this is only generic over the members of the fields array. This means you don't have to go fishing with U[number] to get the union of keys.

It also uses the Pick utility type which saves you from having the complex looking mapped return type.

Playground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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