我试图使类型取决于所传递参数的类型。 一个人为的例子是:
type NS = "num" | "str"
type Data<T extends NS> = T extends "num" ? number : string
type Func<T extends NS> = (x: Data<T>) => Data<T>
type Funcs = {[T in NS]: Func<T>}
type Obj = {[T in NS]: Data<T>}
const funcs: Funcs = {
num: (x) => x * 2,
str: (x) => x + x
}
function useFunc<T extends NS>(ns: T, obj: Obj): Data<T> {
const f = funcs[ns]
const x = obj[ns]
return f(x)
}
问题是f(x)
的类型为number | string
而不是Data<T>
,这似乎是由f
的类型为Funcs[T]
而不是Func<T>
引起的。 x
的类型也为Obj[T]
,而不是Data<T>
。
因此即使Funcs[T]
和Func<T>
和Obj[T]
和Data<T>
和Funcs
是相同的,并且Obj
和function useFunc<T extends NS>(ns: T, obj: Obj): Data<T> {
const f = funcs[ns] as Func<T>
const x = obj[ns] as unknown as Data<T>
// note the double-cast as Obj[T] and Data<T> "do not sufficiently overlap"
return f(x)
}
是相同的,打字稿也不能推断出它们相同。 function useFunc<T extends NS>(ns: T, obj: Obj): Data<T>
function useFunc(ns: NS, obj: Obj): Data<NS> {
if (ns === "num") {
const f = funcs[ns]
const x = obj[ns]
return f(x)
}
const f = funcs[ns]
const x = obj[ns]
return f(x)
}
已定义...
我可以通过类型转换使它正常工作,但是它违反了使用类型的目的:
IIF([Data From System$].[Data Dim#] IS NULL,
[Data From System$].[Data Dim#]
) AS [Value]
有没有办法使它在打字稿中起作用?
编辑:
我知道可以通过这种方式使其工作,并且可以在调用站点上使用,但是从代码重用的角度来看毫无意义-在不同类型上组合相同的逻辑是这样做的实际动力,并且这样就可以简单地重复。
IIF()
有没有办法避免这种重复而又不会失去类型安全性?
答案 0 :(得分:0)
主要问题是,当TS推断f
签名为useFunc
时,您试图在f
内部调用(x: never) => string | numer
函数。此签名与funcs
对象中的每个签名都不兼容。
另外,正如我所说,应将签名useFunc<T extends NS>(ns: T, obj: Obj): Data<T>
简化为useFunc<T extends NS>(ns: T, obj: Data<T>): Data<T>
,甚至最好将其更正。这是因为TS应该知道您将传递给f
的数据的类型,以便能够进行类型检查。另外,另一个需要进行上述修改的原因是useFunc
函数调用仅在ns
等于"num"
或"str"
的情况下可用,但不能同时使用。由于上述原因,obj
参数类型将为Data<"num">
或Data<"str">
。因此,将其键入为Obj
是错误的。
可能的更改最少的解决方案是:
function useFunc<T extends NS>(ns: T, arg: Data<T>): Data<T> {
const f = funcs[ns]
return (f as Func<T>)(arg)
}