typescript - 定义一个数组,其推断类型与数组中的第一个道具相关
问题描述
我需要的是:
- typecirpt 理解每个内部数组的第一个元素是一个 prop create(因此具有自动完成功能)
- 每个内部数组的第二个元素是使用传递的对象类型(realHero)和第一个参数的 prop 键入的,因此,如果我通过
["name", ...
] typescript 必须只接受reader<string>
,因为realHero["name"]
是string
- API级别的最终结果没有改变
这是我的代码
enum HeroSex {
male,
female,
unknown,
}
interface Hero {
name: string;
age: number;
sex: HeroSex;
}
type reader<T> = (value: T) => void;
//the problem is 99% here :(
type readers<T, K extends keyof T> = [prop: K, readerFn: reader<T[K]>];
const readString: reader<string> = (value: string) => {
console.log(`the string is ${value}`);
};
const readNumber: reader<number> = (value: number) => {
console.log(`the number is ${value.toFixed()}`);
};
const readHeroSex: reader<HeroSex> = (value: HeroSex) => {
console.log(`the enum is ${value.toString()}`);
};
const readProperties = <T>(Obj: T, readers: readers<T, keyof T>[]) => {
for (const [prop, reader] of readers) {
reader(Obj[prop]);
}
};
const realHero: Hero = {
name: "batman",
age: 38,
sex: HeroSex.male,
};
//expected result (for the moment is not working)
readProperties(realHero, [
["age", readNumber], //ok
["name", readString], //ok
["sex", readNumber], //typescript error
]);
readProperties(realHero, [
["age", readNumber], //ok
["name", readString], //ok
["sex", readHeroSex], //ok
]);
解决方案
请让我知道它是否适合您:
enum HeroSex {
male,
female,
unknown,
}
interface Hero {
name: string;
age: number;
sex: HeroSex;
}
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type UnionToOvlds<U> = UnionToIntersection<
U extends any ? (f: U) => void : never
>;
type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never;
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
: [T, ...A];
type MapPredicate<T> = T extends keyof Hero ? [T, (arg: Hero[T]) => any] : never
type Mapped<
Arr extends Array<unknown>,
Result extends Array<unknown> = []
> = Arr extends []
? []
: Arr extends [infer H]
? [...Result, MapPredicate<H>]
: Arr extends [infer Head, ...infer Tail]
? Mapped<[...Tail], [...Result, MapPredicate<Head>]>
: Readonly<Result>;
;
type Data<T> = Mapped<UnionToArray<keyof T>>
const makeData = <T,>(Obj: T, readers: Data<T>) => { };
const hero: Hero = {
name: "batman",
age: 38,
sex: HeroSex.male,
};
const result1 = makeData(hero, [
['name', (arg: string) => null],
['age', (arg: number) => null],
['sex', (arg: HeroSex) => null]
])
const result2 = makeData(hero, [
['name', (arg: number) => null], // error
['age', (arg: number) => null],
['sex', (arg: HeroSex) => null]
])
在这里您可以找到更多解释。
致谢:Shanon Jackson,Titian Cernicova-Dragomir,@jcalz
在我的示例中,您应该为所有键定义回调,如果您想让它更通用,您可以使用可选运算符。只需将上面的Mapper
util 替换为 next:
type Mapped<
Arr extends Array<unknown>,
Result extends Array<unknown> = []
> = Arr extends []
? []
: Arr extends [infer H]
? [...Result, MapPredicate<H>?] // <-- added question mark
: Arr extends [infer Head, ...infer Tail]
? Mapped<[...Tail], [...Result, MapPredicate<Head>?]> // <--- added question mark
: Readonly<Result>;
;
推荐阅读
- office365 - Graph API office365移动邮件
- symbolic-math - 将集合转换为表达式 Maple/ 将前缀更改为 In-fix 表达式
- javascript - 使用 webpack 块时 vue 应用程序不更新
- html - 简单的 HTML 和 CSS 问题 - 文本对齐不起作用?
- spring - 版本属性工作正常但未保存在 Couchbase
- php - 将依赖项隐藏在外观后面时,正确的命名约定是什么?
- typo3 - RealUrl - 语言路径段
- redirect - web.config 重定向有问题;500内部服务器错误
- php - PHP PDO 程序
- c# - 拖动时旋转和调整窗口大小