obi*_*ahn 5 generics types typescript typescript-generics conditional-types
我想在数组中键入对象,以便对象的一个属性(此处)隐式定义每个对象的foo另一个属性()的类型。bar
那可能吗?
type Foo<T> = {
foo: T;
bar: T;
};
const foos: Foo<any>[] = [ // <-- What to put here instead of "any"?
{ foo: "text", bar: "this is ok"},
{ foo: 666, bar: "this is NOT ok" }, // <-- should show error (must be of type number)
];
Run Code Online (Sandbox Code Playgroud)
在示例中foo具有bar相同的类型,在我的真实案例场景中我有:
type Column<TData, TValue> = {
accessorFunction: (data:TData) => TValue,
cell: (info:TValue) => any
}
const columns = [
{
accessorFunction: ()=> "test",
cell: (info) => info // <-- info should be of type string
]
Run Code Online (Sandbox Code Playgroud)
但我想这也有同样的打字问题。
(我将重点关注您的Column示例并忽略Foo,因为推理问题不同,并且您关心的Column不仅仅是Foo)。
从概念上讲,类似“对象的集合,其中每个对象都是我知道Column<D, V>的特定类型D,但对于某些V我不关心的类型”需要存在量化的泛型类型。(我想你需要知道D,因为如果你不知道,就没有办法打电话accessorFunction)。
但很少有语言支持此类类型,TypeScript 也不支持;有关相关功能请求,请参阅microsoft/TypeScript#14466 。如果我们确实有它们,你可以这样说Array<Column<D, exists V>>。但我们不这样做,所以我们不能。
有多种方法可以对存在类型进行编码。使用类数据结构通过通用回调反转控制流的一般方法。泛型函数允许调用者指定类型参数,而实现者只知道它是某种类型。它看起来像这样:Promise
type SomeColumn<D> = <R>(cb: <V>(col: Column<D, V>) => R) => R;
Run Code Online (Sandbox Code Playgroud)
ASomeColumn<D>就像 aPromise<Column<D, ??>>的then()方法。它接受回调,然后可能Column<D, V>对其所持有的底层证券调用回调。要将 a 转换Column<D, V>为 a SomeColumn<D>,我们可以使用辅助函数:
const someColumn = <D, V>(col: Column<D, V>): SomeColumn<D> => cb => cb(col);
Run Code Online (Sandbox Code Playgroud)
那么你的数组可能看起来像这样:
const columns = [
someColumn({
accessorFunction: (a: string) => "test",
cell: (info) => info.toUpperCase()
}),
someColumn({
accessorFunction: (a: string) => a.length,
cell: info => info.toFixed(2)
})
];
Run Code Online (Sandbox Code Playgroud)
那columns是类型SomeColumn<string>。如果我们想处理该数组,我们必须添加一个嵌套回调。说吧,像这样:
const results = columns.map(
sc => sc(
col => col.cell(col.accessorFunction("hello"))
)
)
// const results: any[]
console.log(results); // ["TEST", "5.00"]
Run Code Online (Sandbox Code Playgroud)
Column<string, V>请注意,我正在做我能在我不知道的地方做的唯一有用的事情V......那就是,调用col.cell(col.accessorFunction(someString)). 无论如何,results是一个输出数组cell()(您输入为any,所以我们有any[])。
这对于您的用例来说可能有点过分了。也许您关心的只是cell()方法输入的推断,并且您不介意是否columns是像 那样的数组Array<Column<string,string> | Column<string, number>>。Promise如果是这样,您可以保留辅助函数,但只需从中删除任何类似的行为即可。它接受 aColumn<D, V>并返回 a Column<D, V>:
const column = <D, V>(col: Column<D, V>) => col;
const columns = [
column({
accessorFunction: (a: string) => "test",
cell: (info) => info.toUpperCase()
}),
column({
accessorFunction: (a: string) => a.length,
cell: info => info.toFixed(2)
})
]; // okay
Run Code Online (Sandbox Code Playgroud)
但你会发现很难以编程方式处理这些:
const results = columns.map(
col => col.cell(col.accessorFunction("hello")) // error!
// -----------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// compiler doesn't know that this will always be the right type for col.cell
);
Run Code Online (Sandbox Code Playgroud)
那里也有解决方法,但它们很烦人,如果你小心正确地这样做,你也可以使用类型断言:
const results = (columns as Array<Column<string, any>>).map(
col => col.cell(col.accessorFunction("hello"))
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
573 次 |
| 最近记录: |