简体   繁体   English

如何在 TypeScript 中返回泛型

[英]How to return a generic type in TypeScript

What I want to achieve:我想要实现的目标:

  1. A "basic type": Payload, that can be extended by subtypes. “基本类型”:有效负载,可以通过子类型进行扩展。
  2. A method: createPayloadWithData, that takes some data and returns a subtype of payload.一种方法:createPayloadWithData,它获取一些数据并返回有效负载的子类型

What I have tried:我试过的:

const createGUID = (): string => {
  return "";
};

const callService = (path: string, payload: Payload): void => {
  //
};

type Payload = {
  id: string;
  timeStemp: number;
  asyncCall: boolean;
};

function createPayloadWithData<T extends Payload>(
  id: string,
  asyncCall: boolean,
  data?: {}
): T {
  let ts = Date.now();
  let payload = { id, asyncCall, timeStemp: ts, ...data };
  return payload; "//<--- TS error: { id: string; asyncCall: boolean; timeStemp: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Payload
}"

const registerUser = (username: string) => {
  const userId = createGUID();
  const payload = createPayloadWithData(userId, false, { username });
  callService("users", payload);
};

const updateRecords = (records: number[]) => {
  const recordsId = createGUID();
  const payload = createPayloadWithData(recordsId, true, { records });
  callService("records", payload);
};

registerUser("john");
updateRecords([1, 2, 3]);

(In sandbox: https://codesandbox.io/s/ecstatic-bas-97ucu?file=/src/index.ts ) (在沙盒中: https://codesandbox.io/s/ecstatic-bas-97ucu?file=/src/index.ts

TS throws an error for the return value of createPayloadWithData. TS针对createPayloadWithData的返回值抛出错误。 Please allow me to say that I know WHY it does not work.请允许我说我知道为什么它不起作用。 I understand the logic and I have read the wonderful explanation here: could be instantiated with a different subtype of constraint 'object'我理解其中的逻辑,并且在这里阅读了精彩的解释: 可以使用约束“对象”的不同子类型进行实例化

What I don't understand, is how to do it correctly.我不明白的是如何正确地做到这一点。 Would really appreciate your help.非常感谢您的帮助。 Thanks!谢谢!

The problem here is that generic defined like that: T extends Payload .这里的问题是泛型定义如下: T extends Payload

It means T can contain more properties but id , timeStemp and async for sure and returned T has to respect it.这意味着T可以包含更多属性,但idtimeStempasync是肯定的,返回的T必须遵守它。

type PayloadMore = Payload & {required: boolean};

const result: PayloadMore = createPayloadWithData<PayloadMore>('', false);
// but it won't work because `required` isn't present in the return value.

The way you need to do it is to move data as generic and unite it in the return您需要做的是将data作为通用数据移动并将其合并到返回中

const createGUID = (): string => {
  return "";
};

const callService = (path: string, payload: Payload): void => {
  //
};

type Payload = {
  id: string;
  timeStemp: number;
  async: boolean;
};

// optional case
function createPayloadWithData(
    id: string,
    async: boolean
): Payload;
// case with data
function createPayloadWithData<T extends object>(
    id: string,
    async: boolean,
    data: T
): Payload & T;
// implementation
function createPayloadWithData(
  id: string,
  async: boolean,
  data?: {}
): Payload {
  let ts = Date.now();
  let payload = { id, async, timeStemp: ts, ...data };
  return payload;
}

const registerUser = (username: string) => {
  const userId = createGUID();
  const payload = createPayloadWithData(userId, false, { username });
  payload.username // <- now it works
  callService("users", payload);
};

const updateRecords = (records: number[]) => {
  const recordsId = createGUID();
  const payload = createPayloadWithData(recordsId, true, { records });
  payload.id // <- now it works
  payload.records // <- now it works
  callService("users", payload);
};

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

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