typescript 受类型约束的泛型键访问器

bmp9r5qi  于 2023-05-19  发布在  TypeScript
关注(0)|答案(2)|浏览(112)

我想写一个泛型函数,使用类型安全函数返回布尔属性的值,但最终编译器告诉我他不识别我的值的类型。

type KeyOfType<T, V> = keyof {
  [P in keyof T as T[P] extends V ? P : never]: any
}

function getBooleanValue<T, K extends KeyOfType<T, boolean>>(obj: T, propName: K): boolean {
  return obj[propName]
//         ^
// Type 'T[K]' is not assignable to type 'boolean'.
//   Type 'T[keyof { [P in keyof T as T[P] extends boolean ? P : never]: any; }]' is not assignable to type 'boolean'.
//     Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'boolean'.
//       Type 'T[string]' is not assignable to type 'boolean'.(2322)
}

Playground
如果可能的话,我想避免将其转换为obj[propName] as unknown as boolean
谢谢你的帮助!
编辑,因为缺少上下文:此操作是在泛型函数中完成的

type KeyOfType<T, V> = keyof {
  [P in keyof T as T[P] extends V ? P : never]: any
}

export function compareByBooleanProperty<T, K extends KeyOfType<T, boolean>>(
  propName: K,
): (a: T, b: T) => number {
  const propertyAccessor = (obj: T) => obj[propName]
  const booleanComparator =  compareBooleans
  return (a: T, b: T) => {
    const aValue = propertyAccessor(a)
    const bValue = propertyAccessor(b)
    return booleanComparator(aValue, bValue)
//                            ^
// Type 'T[K]' is not assignable to type 'boolean'.
//   Type 'T[keyof { [P in keyof T as T[P] extends boolean ? P : never]: any; }]' is not assignable to type 'boolean'.
//     Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'boolean'.
//       Type 'T[string]' is not assignable to type 'boolean'.(2322)
  }
}

function compareBooleans(a: boolean, b: boolean): number {
  // algorithm
  return 0
}

type Person = {
  name: string
  isMarried: boolean
}

compareByBooleanProperty<Person, "isMarried">("isMarried") // comparator function by

新的Playground版本

zpqajqem

zpqajqem1#

如果只是过滤掉K,编译器不会推断T[K]是布尔型;这就是为什么你还应该输入T;在我们的例子中,T extends Record<K, boolean>就足够了,因为我们不关心其他键,我们只关心T[K]必须是布尔值。

export function compareByBooleanProperty<
  T extends Record<K, boolean>,
  K extends KeyOfType<T, boolean>,
>(propName: K): (a: T, b: T) => number {
// ...
}

playground

jgwigjjp

jgwigjjp2#

将函数的返回类型更改为T[K]而不是boolean

type KeyOfType<T, V> = keyof {
  [P in keyof T as T[P] extends V ? P : never]: any;
}

function test<T, K extends KeyOfType<T, boolean>>(obj: T, propName: K): T[K] {
  return obj[propName];
}

type X = KeyOfType<Person, boolean>

type Person = {
  name: string;
  isMarried: boolean;
}
const p: Person = { name: "Nainpo", isMarried: false };
test(p, "isMarried");
test(p, "name");

Playground链接

相关问题