#Generic map: Type '...' cannot be used to index type '...'

10 messages · Page 1 of 1 (latest)

meager flicker
#

Hi guys,

I'm trying to map field types to the types of their prefixed versions, eg

type Name = {
  firstNameEnabled: boolean
}

type FirstName = {
  enabled: Name['firstNameEnabled']
}

Except that FirstName's properties are inferred from Name, so if I added firstNameFoo to Name, foo is automatically inferred for FirstName.

I'm getting "Type '${S}${Capitalize<key>}' cannot be used to index type 'F'" but I can't fathom why, any ideas?

Thanks!

daring prawnBOT
#
mashmango#0

Preview:```ts
type StartsWith<
HayStack extends string,
Needle extends string

= HayStack extends ${Needle}${string}
? HayStack
: never

/**

  • eg. required => firstNamerequired
    */
    type AddPrefix<
    Prefix extends string,
    Str extends string

= ${Prefix}${Str}
...```

meager flicker
#

I think maybe I'm misunderstanding what extends does.

I was thinking that it narrows the type but it actually widens it?

ie. i thought if Field = Field_Name | Field_Address, then

type<F extends Field> means that F is either Field_Name or Field_Address

but actually it's more like F is Field_Name | Field_Address & { anything else... } ...right?

untold geyser
#

@meager flicker No, you were more right the first time. extends can be read as "is a subtype of"

meager flicker
#

Really? Copilot agreed with that summation but I'm starting to not trust a word it says about typescript! I'll do some more digging on that ty

#

I'm not sure how exactly but I've managed to suppress the error using this: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#key-remapping-via-as

So instead of

type SubField<
  F extends FieldsWithSubfields,
  S extends SubFieldType<F>,
> = {
  [key in UnprefixedNarrowedKey<F, S>]: F[AddPrefixCapitalized<S, key>];
};

its

type MySubField<
  F extends FieldsWithSubfields,
  S extends SubFieldType<F>
> = {
  [key in NarrowedKey<F, S> as RemovePrefixUncapitalized<S, key>]: F[key]
};
untold geyser
#
interface X {
   x: string;
}

// Same as `type XY = X & { y: string }`
interface XY extends X {
   y: string;
}
meager flicker
#

Ahh, sounds like that was the crux of my misunderstanding! Tyvm

So I guess the error was basically TS saying that although it can determine if firstNameFoo exists on FieldsWithSubfields, F can have properties that FieldsWithSubfields doesn't, and by looping though with them with key in F it can't guarantee that the mapped version of those extra properties exists.

ie. F could have property foo but won't necessarily have firstNameFoo

#

Thanks again @untold geyser , I'll resolve this