Create a key union type with keyof typeof from an object that specifies the type of value

Asked 2 years ago, Updated 2 years ago, 39 views

There is an object of type value.

export type SingleTextEditorParamList={
  title:string;
  value:string | undefined;
  onSubmit:(text:string)=>Promise<void>;
  note?—React.ReactNode;
};

const SingleTextEditorParams:Record<string, SingleTextEditorParamList>={
  a: {...omitted},
  b: {...omitted},
  c: {...omitted},
  d: {...omitted} 
};

Is it possible to create a a|b|c|d type from SingleTextEditorParams?


typeSingleTextEditorParamKey=keyoftypeofSingleTextEditorParams;

This will be string.

const SingleTextEditorParams: {[key:string]:SingleTextEditorParamList} = {omitted}

I tried this too, but now string|number.

 type SingleTextEditorParamKeys=a|b|c|d;

const SingleTextEditorParams: { [key in SingleTextEditorParamKey]: SingleTextEditorParamList} = {omitted}

If so, I don't want to add keys to two places because it's redundant. Please let me know if there's a way.

typescript

2022-09-29 20:26

3 Answers

Create SingleTextEditorParams without type annotation first and
How about SingleTextEditorParamKeys as keyoftypeofUntypedSingleTextEditorParams?

const UntypedSingleTextEditorParams={
    a: ...,
    b: ...,
    c:...,
    d:...,
};

type SingleTextEditorParamKey=
    keyof type of UntypedSingleTextEditorParams;

const SingleTextEditorParams
    : Record<SingleTextEditorParamKey, SingleTextEditorParamList>
    = UntypedSingleTextEditorParams;


2022-09-29 20:26

First of all: Record<string, SingleTextEditorParamList> is almost identical to {[key:string]:SingleTextEditorParamList}.See official document for more information on the meaning of Record.

To resolve the issue, simply remove the SingleTextEditorParams type and add typeSingleTextEditorParamKeys=keyoftypeofSingleTextEditorParams.Since the current SingleTextEditorParams is Record<string, SingleTextEditorParamList>, the result of keyoftypeofSingleTextEditorParams is string.


2022-09-29 20:26

There seems to be no direct way.

There is no syntax to infer only the key type

To achieve the behavior of the question, you need the syntax to specify the type of property value (Foo) and to infer the type of key from the substituting object literal, as follows:

const fooRec:Record<Inference here, Foo>={
    a: {prop: "string",
    b: {prop: "string",
    c:{prop:"string",
}

However, there is no such syntax.Several requests have been made in the issue.

How to Use Generic Function Calls

An alternative is to have them deduce everything without describing the type, as stated in the existing answer.In this case, the type check is done when the variable is used, so the error is slightly different from the ideal.

If you want to perform a type check where you write object literals as much as possible, you can use generic function calls.When calling generic functions, it is convenient to check the type of arguments while allowing the generic part to reason.

Example:

 type Foo={
    prop:string
}

// Use the type of Record key as T and make inferences at the calling point.
function initFooRec<Textends string>(x:Record<T,Foo>):Record<T,Foo>{
    return x
}

// where fooRec is Record<"a"|"b"|"c", Foo>
const fooRec = initFooRec({
    a: {prop: "string",
    b: {prop: "string",
    c:{prop:"string",

    // If you enter a non-Foo value as shown below, it can be detected as an error.
    // d:{prop:"string", x:123},
})

// FooRecKeys is "a" | "b" | "c"
type FooRecKeys = keyof type of fooRec

The initFooRec used to infer key types is an equal function that simply returns arguments.You can add any runtime action.


2022-09-29 20:26

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.