【问题标题】:Instruct TypeScript Which Return Type is Expected指示 TypeScript 需要哪种返回类型
【发布时间】:2021-09-19 01:04:01
【问题描述】:

我有一个可以返回几种不同类型的函数,我想使用参数指定返回:


type returnTypes = 'string' | 'object';

function getValue(returnType: returnTypes): string | Record<string, string> {
  if(returnType === 'object') {
    return { my: 'return value' }
  }
  return 'my return value';
}

interface IData {
  myObjectValue: Record<string, string>;
  myStringValue: string;
}
const data: IData = {
  myObjectValue: getValue('object'),
  myStringValue: getValue('string'),
}

TypeScript Playground

data 的分配给我带来了以下错误:

键入'字符串 | Record' 不可分配给类型 'Record'。 类型 'string' 不可分配给类型 'Record'。

键入'字符串 | Record' 不可分配给类型 '细绳'。类型 'Record' 不可分配给类型 '字符串'

大概是因为 TypeScript 认为 getValue 的返回值比我的接口中定义的类型要宽。

如何根据我的 returnType 参数指示 TypeScript,我将收到两种返回类型中的哪一种?

(或者是否有更规范的方式来做到这一点,例如,只是分成功能,如果是这样的话/如何?

【问题讨论】:

  • 我不认为你想要做的事情是可能的,因为打字系统纯粹是一个编译时系统,没有运行时影响。仅在运行时测试 returnType 是什么。

标签: javascript typescript types


【解决方案1】:

你可以使用重载...

function getValue(returnType: 'object'): Record<string, string>
function getValue(returnType: 'string'): string
function getValue(returnType: 'string' | 'object'): string | Record<string, string> {
  if(returnType === 'object') {
    return {my: 'return value'}
  }
  return 'my return value';
}

interface IData {
  myObjectValue: Record<string, string>;
  myStringValue: string;
}
const data: IData = {
  myObjectValue: getValue('object'),
  myStringValue: getValue('string'),
}

或具有条件返回类型的泛型,但在返回时必须在实现中进行断言...

type returnTypes = 'string' | 'object';

function getValue<T extends returnTypes>(returnType: T): T extends 'string' ? string : Record<string, string> {
  if(returnType === 'object') {
    return {my: 'return value'} as any
  }
  return 'my return value' as any;
}

interface IData {
  myObjectValue: Record<string, string>;
  myStringValue: string;
}
const data: IData = {
  myObjectValue: getValue('object'),
  myStringValue: getValue('string'),
}

【讨论】:

  • 这是什么意思:T extends 'string' ? string : Record&lt;string, string&gt;?
  • @1252748 这是conditional type。我用更简单的术语可以将其解释为“如果T'string' 返回string 否则Record&lt;string, string&gt;”。如果'string' 部分令人困惑,您也可以写成T extends 'object' ? Record&lt;string, string&gt; : string
【解决方案2】:

打字稿编译器不会通过您传入的参数值来推断函数的返回类型。这只会在运行时进行评估。

所以它总是假定返回的类型是string | Record&lt;string, string&gt;。你可以做的是在接收站点使用Type Assertion,告诉打字稿,期望什么类型。

type returnTypes = 'string' | 'object';

function getValue(returnType: returnTypes): string | Record<string, string> {
  if(returnType === 'object') {
    return { my: 'return value' }
  }
  return 'my return value';
}

interface IData {
  myObjectValue: Record<string, string>;
  myStringValue: string;
}
const data: IData = {
  myObjectValue: getValue('object') as Record<string, string>,
  myStringValue: getValue('string') as string,
}

当然,这样的类型断言并不能保证这将在运行时起作用。因为如果你的getValue方法有错误,即使参数是object,你也返回了string,这会导致后续错误,当你尝试访问myObjectvalue.my

“最干净”的解决方案可能是定义两个不同的函数,一个返回string,另一个返回Record&lt;string, string&gt;

【讨论】:

    猜你喜欢
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多