typescript 从字符串文字类型参数返回类型

z9smfwbn  于 2023-04-22  发布在  TypeScript
关注(0)|答案(2)|浏览(154)
function assertNever(x: never): never {
  throw new Error('Should never occur.')
}

type StudentMessage =
  | 'get-grades'
  | 'get-best-grade'
  | 'add-grade'

type MessageFunction<TMessage extends StudentMessage> =
  TMessage extends 'get-grades'
  ? () => number[]
  : TMessage extends 'get-best-grade'
  ? () => number
  : TMessage extends 'add-grade'
  ? (grade: number) => void
  : never

function Student(grades: number[]){
  const _grades = [...grades];

  return function<TMessage extends StudentMessage>(message: TMessage): MessageFunction<TMessage> {
    switch(message){
      case 'get-grades':
        return () => _grades;

      case 'get-best-grade':
        return () => Math.min(..._grades);

      case 'add-grade':
        return (grade: number) => {_grades.push(grade)};

      default:
        assertNever(message)
    }
  }
}

我得到以下错误:

Type '() => number[]' is not assignable to type 'MessageFunction<TMessage>'.
Type '() => number' is not assignable to type 'MessageFunction<TMessage>'.
Type '(grade: number) => void' is not assignable to type 'MessageFunction<TMessage>'.

我不明白,为什么TypeScript确实推断出了正确的类型,但仍然在switch语句中的return语句中抛出Error。

cnjp1d6j

cnjp1d6j1#

函数签名

function<TMessage extends StudentMessage>(message: TMessage): MessageFunction<StudentMessage>

switch的返回case都来自case的特定类型StudentMessage,从某种意义上说,你已经“删除”了TMessage

hfsqlsce

hfsqlsce2#

对于这种情况,需要使用泛型重载

function assertNever(x: never): never {
    throw new Error('Should never occur.')
}

type StudentMessage =
    | 'get-grades'
    | 'get-best-grade'
    | 'add-grade'

type MessageFunctionMap = {
    'get-grades': () => number[]
    'get-best-grade': () => number
    'add-grade': (grade: number) => void
}

function Student(grades: number[]) {
    const _grades = [...grades];

    return f;
    function f<TMessage extends StudentMessage>(message: TMessage): MessageFunctionMap[TMessage];
    function f(message: StudentMessage): MessageFunctionMap[StudentMessage] {
        switch (message) {
            case 'get-grades':
                return () => _grades;

            case 'get-best-grade':
                return () => Math.min(..._grades);

            case 'add-grade':
                return (grade: number) => { _grades.push(grade) };

            default:
                assertNever(message)
        }
    }
}

相关问题