簡體   English   中英

打字稿無法為具有 hasOwnProperty 類型縮小的對象鍵賦值

[英]Typescript can't assign value to object key with hasOwnProperty type narrowing

我用類型縮小定義了hasOwnProperty

function hasOwnProperty<
  Obj extends Record<string, any>,
  Prop extends PropertyKey,
>(
  obj: Obj,
  prop: Prop,
): obj is Obj & Record<Prop, any> {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

我期望這樣一個簡單的函數可以工作:

function addProp<T>(obj: Record<string, any>, key: string, val: any) {
  if (!hasOwnProperty(obj, key)) {
    obj[key] = val;
  }
}

但是,我得到Type 'any' is not assignable to type 'never'.

TS游樂場

這是有道理的,因為類型縮小是說obj中不存在key 但是,這不應阻止我添加密鑰。 有什么我做錯了嗎?

編輯:此外,它也不能在函數之外工作:

const obj: Record<string, number> = {};
const key = 'key';
if (!hasOwnProperty(obj, key)) {
  obj[key] = 123;
}
function hasOwnProperty<
  Obj extends Record<string, any>,
  Prop extends PropertyKey,
>(
  obj: Obj,
  prop: Prop,
): obj is Obj & Record<Prop, any> {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}


function addProp<T>(obj: Record<string, any>, key: string, val: any) {
  if (!hasOwnProperty(obj, key)) {
    obj // <---------------- is infered to never
    obj[key] = val;
  }
}

在您的情況下,條件語句后的obj推斷為never 為什么?

因為key類型是字符串,而!hasOwnProperty(obj, key)意味着obj沒有更多的string鍵。

如何解決?

您可以為key參數添加顯式泛型。

function addProp<T, Prop extends string>(obj: Record<string, any>, key: Prop, val: any) {
  if (!hasOwnProperty(obj, key)) {
    obj[key] = val;
    return obj
  }
  return obj
}


const x = addProp({}, 'a', 42) // Record<string, any> & Record<"a", any>

在這里,在我的博客中,您可以在打字稿中找到更多關於突變的問題

@captain-yossarian 的答案適用於我可以為密鑰使用泛型的函數。 但是,在我不能使用泛型的地方,它仍然不起作用(請參閱編輯)

這個例子是行不通的:

const obj: Record<string, number> = {};
const key = 'key';
if (!hasOwnProperty(obj, key)) {
  obj[key] = 123;
}

因為您假設key屬性在obj是可選的,所以您應該使用Partial

const obj: Partial<Record<PropertyKey, number>> = {};
const key = 'key';
if (!hasOwnProperty(obj, key)) {
  const x = obj
  obj[key] = 123; // ok
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM