2

Trying to add types to an existing JS library I'm using. The library unfortunately has a rule that the type of the value in an object is somewhat determined by the capitalization of the first letter of its associated key. I thought something like the below might work, but it does not.

type UppercaseLetters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
type LowercaseLetters = Lowercase<UppercaseLetters>;

type RefKey = `${UppercaseLetters}${string}`
type PropKey = `${LowercaseLetters}${string}`

// Define these types just so it compiles
type SomeRefType = number;
type SomePropType = boolean;

type Spec = {
  type: string
} & {
  [s in RefKey]: SomeRefType
} & {
  [s in PropKey]: SomePropType
};

This compiles, but the actual type that Spec becomes is:

type Spec = {
    type: string;
} & {} & {}

Any ideas out there? Perhaps this case is just too out of the left field for TypeScript to handle.

Example object:

const specObj: Spec = {
  type: 'Some string',
  Apple: 3,
  Orange: 6,
  lowerCaseKey: false,
  anotherOne: true
}
11
  • 3
    It should be fixed by this PR when it gets included in a release. In the meantime, I don't see any solution to your problem. Commented Jun 28, 2021 at 15:55
  • 1
    However, trying it out in the playground there still is a conflict between your type property and t${string} Commented Jun 28, 2021 at 16:00
  • 1
    Whoops! Yes a typo. My mind somehow regressed to C Commented Jun 29, 2021 at 14:26
  • 1
    @FrankWeindel - huh, happens. Just asked you because sooner or later people will start bugging you about it :) As for the issue, yeah, you will have to wait until it's live, not much you can do now. Commented Jun 29, 2021 at 14:39
  • 1
    @FrankWeindel - btw, are RefKey and PropKey limited in what they can actually hold? I mean, do they hold arbitrary properties or a fixed set of those? Commented Jun 29, 2021 at 16:14

2 Answers 2

1

As noted by Alateros in the comments, since [email protected] you can use index signatures for template literals.

Though you still have to ensure type field must be required and may have the type that is not compatible with lowercased keys type. So you may write Spec type like that:

type Spec = {
  [K in RefKey | PropKey]: 'type' extends K 
      ? string 
      : K extends RefKey 
          ? SomeRefType 
          : K extends PropKey 
              ? SomePropType
              : never
} & {
  type: string
}

playground link

Sign up to request clarification or add additional context in comments.

1 Comment

Revisiting this now with the release of TS 4.4. Wish it was less complicated but it works! Thanks for the help!
0

I removed

type RefKey = `${UppercaseLetters}${string}`
type PropKey = `${LowercaseLetters}${string}`

and replaced with UppercaseLetters and LowercaseLetters types

enter image description here

Is it what are you looking for?

3 Comments

Sorry no. I'm trying to apply types based on the capitalization of the first letter of a key.
I just saw the example of the result ( output ). Can you show the input/types that you will get?
Not sure I understand what you mean. The example I posted is both the input and output. I'm trying to get TypeScript to treat that as a valid object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.