typescript - Tip korumasında (`hasOwnProperty`) `string`i `T`nin `keyof`una daraltma


Bir nesnenin anahtarı olması gereken bir string kullanıcı girdiğim var.

const validInputOptions = {
    "admin": "Admin",
    "guest": "Guest",
    "restricted": "Restricted Guest",
    "view_only": "Restricted Guest - View Only",
};

const userInput = getUserInput(); // <-- userInput is a string
verify(userInput); // <-- throws new error if user input is invalid
const option = validInputOptions[userInput]; // <-- tsc would still complain here `Element implicitly has an 'any' type because expression of type 'string' can't be used to index type ...`

Sorun, kullanıcı girişinin validInputOptions için güvenli bir şekilde indeks olarak kullanılabileceğini tsc'ye söylemektir

Cevap #1

İşte benim oluşturduğum tür koruyucu (typescript üzerinde resmi bir konu var https://github.com/microsoft/TypeScript/issues/12892, bu konu in operatörü ve hasOwnProperty için tsc'nin neden türü daraltmadığını açıklıyor)

const isKeyOf =
    <ObjectType extends Record<PropertyKey, unknown>>
    (object: ObjectType, property: PropertyKey): property is keyof ObjectType => {
        return Object.prototype.hasOwnProperty.call(object, property);
    };

yani bu kullanım şekli:

if (!isKeyOf(validInputOptions, userInput)) {
    throw new Error(`invalid input`);
}

// now this is safe to use, userInput is narrowed to `keyof typeof validInputOptions`
const option = validInputOptions[userInput];

Cevap #2

Bu da işe yarıyor gibi görünüyor:

function isKeyOf<T extends object>(obj: T, key: PropertyKey): key is keyof T {
  return obj.hasOwnProperty(key)
}