TypeScript条件类型报告类型不可赋值

mwngjboj  于 2023-01-27  发布在  TypeScript
关注(0)|答案(3)|浏览(238)

我试图理解TypeScript条件类型是如何工作的。下面是我的代码。有类型错误:

interface MyType {
  name: string;
}

const testFunc = <T extends MyType | string>(
  what: T
): T extends MyType ? MyType : string => {
  if (typeof what === 'object') {
    return what['name'];
  }
  return what;
};

正确的用法是什么?

uajslkp6

uajslkp61#

你代码中的函数TestFunc应该在任何情况下都返回string。我认为这是一种打字错误。让我们修正它并继续。
后来我想出了一个更安全的解决方案(我把我原来的答案留在底部),最好使用重载,在重载中描述条件逻辑,在函数中使用联合类型。

interface MyType {
  name: string;
}

function testFunc<T extends MyType | string>(
  what: T
): T extends MyType ? string : MyType;

function testFunc(what: MyType | string): MyType | string {
  if (typeof what === 'object') {
    return what.name;
  }
  return { name: what };
}

老答案:

interface MyType {
  name: string;
}

type TestFunc = <T extends MyType | string>(what: T) => T extends MyType ? string : MyType;

const testFunc: TestFunc = (what: any) => {
  if (typeof what === 'object') {
    return what.name;
  }
  return { name: what };
};

或者,如果您希望定义内联类型:

interface MyType {
  name: string;
}

const testFunc: <T extends MyType | string>(what: T) =>
  T extends MyType ? string : MyType =
  (what: any) => {
    if (typeof what === 'object') {
      return what.name;
    }
    return { name: what };
  };

Typescript编译器将这样处理它:

const a1: MyType = testFunc({ name: 'foo' }); // Type 'string' is not assignable to type 'MyType'.

const a2: MyType = testFunc({ name: 1 }); // Error: Argument of type '{ name: number; }'
//                                is not assignable to parameter of type 'string | MyType'

const a3: string = testFunc({ name: 'foo' }); // Ok

const a4: string = testFunc('foo'); // Error: Type 'MyType' is not assignable to type 'string'.

const a5: MyType = testFunc('foo'); // Ok
lmyy7pcs

lmyy7pcs2#

这个答案基本上是用更多的单词和代码解释@jcalz的评论。
您正确地理解了这个概念。不幸的是,您遇到了TS中的一个警告,当通过控制流分析来缩小可能性时,它没有平等地对待具体类型和泛型类型。
理想情况下,你建议的用法应该是有效的。但是TS还不支持它。
现在我们需要变通一下,这是我通常做的。

interface MyType {
  name: string;
}

const testFunc = <T extends MyType | string>(
  _what: T
): T extends MyType ? MyType : string => {
  // First thing to do once enter the fn body,
  // we manually cast to `any` type
  var what = _what as any;
  if (typeof what === 'object') {
    return what['name'];
  }
  return what;
};

不完美,我知道。这有点像你实现了一个重载的函数,最终你只需要使用any类型。但是既然你已经为你的消费者提供了一个完美的函数接口,那么在后台做一点肮脏的事情也没关系。

enyaitl3

enyaitl33#

我会这样做:

interface MyType {
  name: string;
}

const testFunc = <T>(what: T): T extends MyType ? MyType : string => {
    if (typeof what === 'object') {
        return what['name'];
    } 
    return what as any;

};

as any的意思是“TypeScript,don't complaint about this type”。问题是what的缩小类型没有被条件类型拾取,所以函数无法计算条件并将返回类型缩小到what

相关问题