泛型不';在typescript函数中似乎没有充分考虑

泛型不';在typescript函数中似乎没有充分考虑,typescript,Typescript,我有以下设置: export const doQuery = <DocType>({ query }: { query: Query<DocType> }) => { return query.doTheQuery() } DocType可以是A、B或C。但是,我在doQuery中的query上遇到一个错误: Type 'Query<A> | Query<B> | Query<C>' is not assignable to

我有以下设置:

export const doQuery = <DocType>({ query }: { query: Query<DocType> }) => {
  return query.doTheQuery()
}
DocType可以是
A
B
C
。但是,我在
doQuery
中的
query
上遇到一个错误:

Type 'Query<A> | Query<B> | Query<C>' is not assignable to type 'Query<A>'
类型“Query | Query | Query”不可分配给类型“Query”

我不明白typescript是如何认为查询只能是
query
在这种情况下

这里有几个选项,每个选项都有自己的优缺点。第一:

const doQuery = <D extends A | B | C, T extends Query<D>>({ query }: { query: T }): D => {
  return query.doTheQuery()
}
constdoquery=({query}:{query:T}):D=>{
return query.doTheQuery()
}
doQuery实现中的it类型安全性的好处。糟糕的是,当你使用它的时候,它有它的类型故障

function foo(q: Query<A>): A {
    const a = doQuery({query: q}); // Bad: "a" is typed to A | B | C
    const a1: A = a; // Error because A | B | C can not be assigned to A

    const b: B = doQuery({query: q}) // Good: it errors in incompatible query

    const c: A = doQuery({query: q}) // Good: it assignes without typecasting to the correct type
    const c1: A = c // No error
}
函数foo(q:Query):A{
const a=doQuery({query:q});//错误:“a”被键入a | B | C
常数a1:A=A;//错误,因为A | B | C无法分配给A
const b:b=doQuery({query:q})//好:不兼容查询中出现错误
const c:A=doQuery({query:q})//Good:它在不进行类型转换的情况下分配给正确的类型
常数c1:A=c//无错误
}
另一个选择是这样键入

const doQuery = <T extends Query<any>>({ query }: { query: T }): T extends Query<infer V> ? V : never => {
  return query.doTheQuery()
}
constdoquery=({query}:{query:T}):T扩展查询?V:从不=>{
return query.doTheQuery()
}
好:它有最好的用法声明(如选项3)。它始终具有正确的返回类型。坏:在实现内部应该小心

const doQuery = <T extends Query<any>>({ query }: { query: T }): T extends Query<infer V> ? V : never => {
  const result = query.doTheQuery()

  const a = 6 + result; // No error, because "result" on this step inferred as "any"

  return result;
}
constdoquery=({query}:{query:T}):T扩展查询?V:从不=>{
const result=query.doTheQuery()
const a=6+result;//没有错误,因为此步骤上的“result”推断为“any”
返回结果;
}
最后,这里是我最喜欢的一个:

type DoQueryResult<T extends Query<A | B | C>> = T extends Query<infer V> ? V : never;

const doQuery = <T extends Query<A | B | C>>({ query }: { query: T }): DoQueryResult<T> => {
  return result as DoQueryResult<T>;
}
type DoQueryResult=T扩展查询?V:从来没有;
constdoquery=({query}:{query:T}):DoQueryResult=>{
将结果返回为DoQueryResult;
}
它具有前两种解决方案的所有优点,但只有一个缺点:您应该在实现中键入return语句(
结果为DoQueryResult

constdoquery=({query}:{query:T}):DoQueryResult=>{
const result=query.doTheQuery()
常量a=6+结果;//它出错
将结果返回为DoQueryResult;//它将结果推断为A | B | C,我们需要对其进行类型转换
}

请将您的问题设为a。是否有办法在
doQuery
中使用给定类型(a、B或C),或者它是否卡在
Query
中?@ChrisDrackett您能再解释一下您的意思吗,您想要实现什么?基本上,
doQuery
的返回值是一个
A
B
C
的数组,因此我试图找出如何将其应用到您的最终答案中above@ChrisDrackett答案中有三个解决方案。第一个函数为您提供
A | B | C
,而无需您提供额外的帮助,但是,如果您将其分配给具有此类型的变量,它将为您提供正确的类型(并防止您分配到错误的类型,请参见
清单2
)。第二个和第三个解决方案总是为您提供正确的输出类型(它们为
Query
提供
A
Query
提供
B
,等等)。我更喜欢第三种解决方案(
清单5
),但根据它们的优缺点选择哪种解决方案取决于您。
type DoQueryResult<T extends Query<A | B | C>> = T extends Query<infer V> ? V : never;

const doQuery = <T extends Query<A | B | C>>({ query }: { query: T }): DoQueryResult<T> => {
  return result as DoQueryResult<T>;
}
const doQuery = <T extends Query<A | B | C>>({ query }: { query: T }): DoQueryResult<T> => {
  const result = query.doTheQuery()

  const a = 6 + result; // It errors

  return result as DoQueryResult<T>; // It infers result as A | B | C and we need to typecast it
}