#Type object key as T instead of string

13 messages · Page 1 of 1 (latest)

mental steeple
#

Hi, how do I type the key for the return type here?

const getObj = <T extends 'hi' | 'hello'>(value: T) => ({ [value]: value })

const k = getObj('hi') // { [x: string]: T }

https://www.typescriptlang.org/play/?#code/MYewdgzgLgBA5gUygeQEYCsYF4YB4AqMCAHlAmACYQwDkAFgJY0wA+tdCANpyDQHwAKAG4BDTgFcEALhj4AlNj4wBAbxgBtURIQBdGVskwAvnIBQp0JFgBrbPCRp0A+kzNA

I'm not looking to explicitly mention the return type, as the object values call another function with more return types based on inputs

wanton groveBOT
#

@mental steeple Here's a shortened URL of your playground link! You can remove the full link from your message.

orbviox#0

Preview:```ts
const getObj = <T extends "hi" | "hello">(
value: T
) => ({[value]: value})

const k = getObj("hi")```

solemn sphinx
#

can you say more about this?

I'm not looking to explicitly mention the return type, as the object values call another function with more return types based on inputs

#

also what type do you want back specifically?

mental steeple
#

I've got this code:

const getFieldConnection = <T extends z.infer<typeof baseFieldSchema>>(
  data: T,
) =>
  'id' in data
    ? { connect: { ...data, id: data.id } }
    : {
        connectOrCreate: {
          where: data as any,
          create: { ...data, name: data.name },
        },
      };

const getManyToManyConnection =
  <
    T extends 'enum' | 'of' | 'strings',
    TValue extends z.infer<typeof baseFieldSchema>,
  >(
    field: T,
  ) =>
  (values: TValue[]) => ({
    create: values.map(
      (value) =>
        ({ [field]: getFieldConnection(value) }) as {
          [K in T]: ReturnType<typeof getFieldConnection>;
        },
    ),
  });

either I am looking to pass TValue to ReturnType<typeof getFieldConnection> or I just have TypeScript infer it - but have the key as T

solemn sphinx
#

and are you okay with that type assertion? or are you hoping to eliminate it?

mental steeple
#

hoping to eliminate! (as its still weakly typed)

solemn sphinx
#

if you want to avoid assertions this is the best i've come up with, but i bet you won't find it satisfying:

const getObj = <T extends PropertyKey>(value: T) => {
  const result: Partial<Record<T, T>> = {}
  result[value] = value
  return result
}
mental steeple
#

yup, that won't help either.. need the value to be typed according to TValue 😦

solemn sphinx
#

when using dynamic property names i think TS will only infer a specific key when the variable is a constant with exactly one concrete literal string type (i.e. not even a union, let alone a type parameter)

#

like even here x isn't inferred as { a: boolean } | { b: boolean }:

wanton groveBOT
#
declare const key: 'a' | 'b'
const x = { [key]: true }
//    ^? - const x: {
//        [x: string]: boolean;
//    }
mental steeple
#

hmm.. understood. that's unfortunate this bit is lacking - I guess I will need to stick to type assertion!