这种的类型是不是实现不了(TypeScript)

327 天前
 wednesdayco
需求: 一个类型必须包含 id 属性,值的类型为 string ,同时它可能包含其他的属性,但值的类型必须是 number 。
2309 次点击
所在节点    TypeScript
32 条回复
nomagick
327 天前
我解开了


interface NumO {
[k: string]: number;
}

type WithID<T> = {
id: string;
} & T;
type WTF = WithID<NumO>;

const v = {
id: 'wtf'
} as WTF;

// OK
v.id = 'str';
v.a = 3;
v.b = 4;
// Not OK
v.c = 'sr';
gam2046
327 天前
interface A {
id: string;
}

interface B {
[k: string]: number
}

type AB = A & B

function sample(arg: AB) {
arg.id = 'aaa'
arg.bcd = 1234
}
wednesdayco
327 天前
@nomagick 这样做在类型提示上确实是对的,问题在初始化的时候不能加除了 id 以外的属性
nomagick
327 天前
再加一个类型参数,现场合并。。。
真拧巴。。。
rrfeng
327 天前
@gam2046 这样实际上 AB 不存在……,所以是 bug 。
NoManPlay
327 天前
```
type CustomType = {
[key: string]: number | string;
} & {
id: string;
};

// 通过映射类型和条件类型来移除 id 属性外的 string 类型
type StrictCustomType = {
[K in keyof CustomType]: CustomType[K] extends string ? (K extends 'id' ? string : never) : number;
};
```
wednesdayco
327 天前
@NoManPlay 想法很好,但是实际初始化 StrictCustomType 的对象的时候,会报错。
Pencillll
327 天前
对于初始化来说,如果可以加个 helper 函数的话,倒是有一种办法:

type CoercedItem<T> = {
[K in keyof T]: K extends 'id' ? string : number
}

type ValidItem<T> = T extends CoercedItem<T> ? 'id' extends keyof T ? T : never : never

function makeItem<T>(item: ValidItem<T>): T {
return item
}

const a = makeItem({ id: 'x', no: 1 })

a.id = 'y'
a.no = 2

const b = makeItem({ id: 'z' })

// 报错
const c = makeItem({ id: 1, no: 1 })

// 报错
const d = makeItem({ no: 1 })
Pencillll
327 天前
不过上面这样有个缺陷是初始化之后的对象不能再添加新的属性
CLMan
327 天前
好奇什么场景需要这么复杂的类型定义呢?

或者说类似问题的类型约束的严谨性和代码简洁应该如何取舍?

我个人是把 TS 当作一个不太完美的类型约束工具,更倾向于代码简洁性。
Gaoti
326 天前
```ts
type Others = Record<string, number>;

type T<O = Others> = {
id: string;
} & {
[K in keyof O]: K extends "id" ? string : number;
};

const obj: T<{ id: string; aaa: number }> = {
id: "1",
aaa: 123,
bbb: 1, // error
};
```

使用的时候泛型传入对应的类型就行,但是和 #28 说的一样,泛型中没有定义的的字段会报错
chnwillliu
285 天前
const id = ()=> ('i' + 'd ').trim();

const n:number = obj[id()];

如果有这样的类型你这样操作那 TS 该不该报错? key 是运行时决定,所以有可能是 string 也有可能是 number 。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1012854

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX