【问题标题】:Return type strengthening depending on whether optional param is passed返回类型加强取决于是否传递了可选参数
【发布时间】:2018-12-11 00:22:37
【问题描述】:

假设我们需要实现一个返回一些东西的方法,但是当这个东西是undefined时,它应该返回一些传入的默认值。但是我们不想将默认值参数设为必需,因此将其声明为可选参数:

private returnSomething(someParam: string, defaultValue?: string) : string | undefined {
    const result: string | undefined = ...; // Some result-producing logic
    return result !== undefined ? result : defaultValue;
}

我们希望以下内容在严格模式下编译(注意 something1: string 类型,它声明时没有 undefined 部分):

const something1: string = this.returnSomething("someParam1", "?"); // Error, no undefined in the type of something1
const something2: string | undefined = this.returnSomething("someParam2");

是否可以在 TypeScript 中声明一个方法,以便在未传递可选参数时,方法的返回类型被视为 string | undefined,而在传递时,返回类型为 string

【问题讨论】:

  • @NurbolAlpysbayev:谢谢!固定的。这是复制粘贴问题:)

标签: typescript


【解决方案1】:

所以,如果我没记错的话,这很容易使用 generic 类型:

const returnSomething = <D extends string | undefined>(someParam: string, defaultValue?: D) : D extends undefined ? string | undefined : string => {

  const result = {} as any;

  return result !== undefined ? result : defaultValue;
}

playground

UPD 以避免在不使用 any 时出现错误:

const returnSomething = <D extends string | undefined, R extends D extends undefined ? string | undefined : string>(someParam: string, defaultValue?: D) : R => {

  const result = 'str';

  return (result !== undefined ? result : defaultValue) as R;
}

UPD2。正确的方法(我很抱歉搞砸了)。

我想表示歉意,因为我引入了泛型和条件类型,而它们是不必要的。我的意思是,我不知道它们会导致这样的错误。但我也被最初的问题误导了。 所以正常的方式,我会怎么做,看起来像这样:

const returnSomething = (someParam: string, defaultValue?: string): string | undefined => {

    const result = '';

    return result !== undefined ? result : defaultValue;
}

const something1 = returnSomething("someParam1", "?");
const something2 = returnSomething("someParam2");

就是这样。是的,您不应该将类型分配给something1something2。相反,您应该运行时检查(并且打字稿从检查中推断类型):

if (typeof something1 === 'undefined') { 
    /* oops the value is undefined, do something to make the program continue working properly */ 
} 
else {
    something1 // has type "string"
}

关于错误,我已经提交了issue

【讨论】:

  • 谢谢!它消除了 something1: string 案例的错误,但现在我们能够在没有 undefined 部分的情况下声明 something2: string 并且不会产生编译器错误(不能提供整个 Playground 链接,因为评论太长了,但相关部分是:const something2: string = returnSomething("someParam2"); // For some reason, no error)。你也知道如何处理这个案子吗?
  • @AlexanderAbakumov 抱歉,我不明白出了什么问题,您能详细说明一下吗?第二种情况应该产生什么错误?你知道,stringstring | undefined 的一个子集。你能解释一下吗..
  • 当然。当我们调用const something2: string = returnSomething("someParam2"); 时,defaultValue 基本上就是undefined。因此,undefined 可能会从returnSomething() 返回。但是编译器允许我们声明const something2: string = ...,这是不正确的,因为我们知道它是const something2: string | undefined = ...。有意义吗?
  • @AlexanderAbakumov 用户 y2bd 给出了正确答案,我的代码中有一个愚蠢的错误。现已修复。
  • 好吧,我想这个小故障是完全可以理解的 :) 我认为 TS 编译器应该警告我们在这种情况下我们正在做一些毫无意义的事情。希望他们有一天会实施此警告。
【解决方案2】:

Nurbol 已经完成了大部分工作,我必须进行一项额外的更改才能使其充分发挥作用:

const returnSomething = <D extends string | undefined>(someParam: string, defaultValue?: D) : D extends undefined ? string | undefined : string => {
  const result = {} as any;
  return result !== undefined ? result : defaultValue;
}

const something1: string = returnSomething("someParam1", "d"); // No error
const something2: string | undefined = returnSomething("someParam2"); // No error
const something3: string = returnSomething("someParam2"); // Yes error
const something4: string = returnSomething("someParam2", undefined); // Yes error

我们需要先定义D 以接受undefined,否则条件将始终只返回string

这样做的副作用是您现在可以将undefined 作为默认值传递。但它仍然按预期出错。

你也可以通过函数重载来做到这一点:

function returnSomething(param: string): string | undefined;
function returnSomething(param: string, defaultValue: string): string;
function returnSomething(param: string, defaultValue?: string) {
  const result = {} as any;
  return result !== undefined ? result: defaultValue;
}

这避免了undefined 问题。

【讨论】:

  • 是的,正确。很好的解释,顺便说一句!天哪,我很傻。我给了D 类型string 并试图检查它是否是string | undefined 哈哈。
  • 谢谢你们的回答,伙计们!我尝试使用它,但在将const result = {} as any; 行更改为真实案例const result = ""; 时遇到了问题。编译器错误为:Type 'string' is not assignable to type 'D extends undefined ? string : string'。 @NurbolAlpysbayev,您可能也会对此感兴趣。
  • 在函数重载方法中,您没有为returnSomething() 声明特定的返回类型。这可以防止编译器进行编译时类型检查,并随后防止运行时错误。示例:const something2: string | undefined = this.returnSomething("someParam2"); console.log(something2.length); 编译正常,但如果 undefined 将从 returnSomething() 方法返回,则会在运行时失败。
猜你喜欢
  • 1970-01-01
  • 2021-08-11
  • 2021-07-18
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 2022-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多