“R”可以用与

问题描述 投票:0回答:1

如何根据下面的代码推断

R
的返回类型。

export type SequenceDefinition<S extends string> = {
  keys: S[] | Readonly<S[]>,
  actions: Record<S, <R>(data: SequenceData<S, SequenceDefinition<S>>) => R>
}

type SequenceData<S extends string, T extends SequenceDefinition<any>> = {
  get: (key: S) => ReturnType<T['actions'][S]>
}

export type SequenceCreatorFn = <S extends string>(config: SequenceDefinition<S>) => void;

export const sequence: SequenceCreatorFn = (config) => {
  console.log(config);
};

const result = sequence({
  keys: ['load', 'save', 'log'],
  actions: {
    load: () => {. // <- Error here
      return { a: 1, b: 2 };
    },
    save: (data) => { // <- Error here
      data.get('load');
      return true;
    },
    log: () => { // <- Error here
      return 1;
    }
  }
});

错误信息是:

Type '() => { a: number; b: number; }' is not assignable to type '<R>(data: SequenceData<"load" | "save" | "log", SequenceDefinition<"load" | "save" | "log">>) => R'.
  Type '{ a: number; b: number; }' is not assignable to type 'R'.
    'R' could be instantiated with an arbitrary type which could be unrelated to '{ a: number; b: number; }'.
  1. Typescript 在操作方法上返回错误,除非我使用
    any
    unknown
    作为返回类型。
  2. 我希望基于之前的交互对
    data.get
    有一个强类型定义。
typescript-typings typescript-generics type-inference
1个回答
0
投票

Typescript 无法推断 R 的类型,因为它可以是任何类型。如果你以这个功能为例

function test(
// This is the type of your sequence config
config: SequenceDefinition<"load" | "save" | "log">
){
config.actions.load()
}

你可以看到,仅通过输入类型的定义,打字稿无法知道 load 返回什么,相反,任何具有 load、save 和 log 3 个函数的函数都可以分配给

SequenceDefinition<"load" | "save" | "log">
。 解决方案是让您的类型更具辨别力,以便对于每个操作,该函数只能返回单一类型

export type SequenceDefinition<Actions extends Record<string,unknown>> = {
  keys: (keyof Actions)[],
  actions:{
    [key in keyof Actions]: (data: SequenceData<Actions>) => Actions[key]
  } 
}

type SequenceData<Actions extends Record<string,unknown>> = {
  get: <Key extends keyof Actions>(key: Key) => Actions[Key]
}

export type SequenceCreatorFn = <Actions extends Record<string,unknown>>(config: SequenceDefinition<Actions>) => void;

export const sequence: SequenceCreatorFn = (config) => {
  console.log(config);
};

const result = sequence({
  keys: ['load', 'save', 'log'],
  actions: {
    load: () => { 
      return { a: 1, b: 2 };
    },
    save: (data) => { 
      data.get('load');
      return true;
    },
    log: () => { 
      return 1;
    }
  }
});

在这种情况下

SequenceDefinition
不再仅由键定义,还由函数返回的值定义

© www.soinside.com 2019 - 2024. All rights reserved.