Home > OS >  Why won't typescript let me set a value of an object to a string when it recognizes its type is
Why won't typescript let me set a value of an object to a string when it recognizes its type is

Time:09-29

I've constructed the function that accepts an object and a key of that object that is a string. But in the body of the function it will not let me set the value of the object with a different string.

const setAndGetString = <K extends string, T extends Record<Exclude<string, K>, any>>(
  obj: T & Record<K, string>,
  key: K
): string => {
  obj[key] = "foo" // Type 'string' is not assignable to type '(T & Record<K, string>)[K]'.
  return obj[key] // okay
}

Is there a way to adjust the signature so that the assignment will work? (yes, I can cast in the assignment, but that solution isn't great).

https://www.typescriptlang.org/play?ssl=7&ssc=2&pln=1&pc=1#code/MYewdgzgLgBBCmUCCYAmBxRBlKAnAlmAOYwC8MAPANIzwAeU8aEcehRANDACq0NOoWAJXihcqCgFE6wADYBXVPArQCxLlQB8XAIZgAnps0AKAFAwYIAEYArAFw8YAMhgixEql1Xtt5mAGt4fQcqUwBKB29iMk0YAG8-axsAbUD9AF0yGAAiADMQEGyYAHpinn0AB3gYAHIoohqYfBYwEFgdCAh8IjAdK1lqqBAYKErqmuNeFzcQcWovNmJNMOSqdJqAOj9cRHlcMEtbVKDM0st-HX1TAF8gA

CodePudding user response:

You were close.

Consider this example:

/**
 * Obtain a union of all values of record
 */
type Values<T> = T[keyof T]

/**
 * Obtain a union of all object keys which coresponds to strings
 */
type StringProperty<T> = Values<{
  [Prop in keyof T]: T[Prop] extends string ? Prop : never
}>

const setAndGetString = <
  Obj extends Record<PropertyKey, unknown>,
  Key extends StringProperty<Obj>
>(obj: Obj & Record<Key, string>, key: Key) => {
  const result = obj[key].charAt // ok
  return obj[key] // okay
}
const obj = {
  a: 'a',
  b: 42
}

setAndGetString(obj, 'a') // ok
setAndGetString(obj, 'b') // expected error

Playground

  • Related