Description
I want to return either string
or string[]
based on the input parameter. In this case, the input parameter is called options
and it is the input
property: options.input
.
I'm trying to make TypeScript infer it based on this input but I cannot seem to get it to work.
Types
The types are defined like this.
const TextInputTypes = <const>[
"text",
"number",
"password",
"email",
"tel",
"url",
"search",
"color",
"date",
"time",
"datetime-local",
"month",
"week",
"range",
"file",
];
const CheckboxTypes = <const>["checkbox", "radio"];
const SelectTypes = <const>["select"];
type TextType = (typeof TextInputTypes)[number];
type CheckType = (typeof CheckboxTypes)[number] | (typeof SelectTypes)[number];
type InputType = TextType | CheckType;
type PromptOptions = {
input: InputType;
placeholder: string;
entries: { value: string; text: string }[];
};
Example
If options.input
is in TextType, then it returns string
, else it returns string[]
.
Code
I have tried this without making it work
type ReturnType<T extends InputType> = T extends TextType ? string : string[];
const value: ReturnType<typeof options.input>;
It is basically within a function like so:
function foo = (name: string, options: Options) => {}
The output only says string | string[]
.
CodePudding user response:
Use function overloaing.
const TextInputTypes = [
"text",
"number",
"password",
"email",
"tel",
"url",
"search",
"color",
"date",
"time",
"datetime-local",
"month",
"week",
"range",
"file",
] as const;
const CheckboxTypes = ["checkbox", "radio"];
const SelectTypes = ["select"] as const;
type TextType = (typeof TextInputTypes)[number];
type CheckType = (typeof CheckboxTypes)[number] | (typeof SelectTypes)[number];
type InputType = TextType | CheckType;
type PromptOptions<T extends InputType> = {
input: T;
placeholder: string;
entries: { value: string; text: string }[];
};
const isCheckboxType = (typeString: string): typeString is CheckType => (CheckboxTypes as string[]).includes(typeString)
function foo (name: string, options: PromptOptions<TextType>): string
function foo (name: string, options: PromptOptions<CheckType>): string[]
function foo (name: string, options: PromptOptions<TextType | CheckType>): string | string[] {
if (CheckboxTypes.includes(options.input as CheckType)) {
// TODO
return ''
}
// transformToDocument
return []
}
const arrayExample = foo('test', {input: 'select', placeholder: 'test', entries: []})
const stringExample = foo('test', {input: 'text', placeholder: 'test', entries: []})
CodePudding user response:
Alternatively to the answers from @JDB and @adsy, you can use extends
to achieve your goal:
type StringOrArrayString<T extends PromptOptions> = T extends {input: TextType} ? string : string[];
function foo<T extends PromptOptions>(name: string, options: T): StringOrArrayString<T> {
// ...
}
CodePudding user response:
You can use function overloads to detect the type of the input
property and then return either a string
or a string[]
. Note that this requires changing from an anonymous function (const foo = () => {}
) to a named function (function foo() {}
).
function isTextType(inputType:string):inputType is typeof TextInputTypes[number] {
return (TextInputTypes as readonly string[]).includes(inputType);
}
type PromptOptions = {
placeholder: string;
entries: { value: string; text: string }[];
}
type TextTypePromptOptions = PromptOptions & {
input: TextType;
};
type CheckTypePromptOptions = PromptOptions & {
input: CheckType;
}
function foo(name:string, options:TextTypePromptOptions):string;
function foo(name:string, options:CheckTypePromptOptions):string[];
function foo(name:string, options:TextTypePromptOptions|CheckTypePromptOptions):string|string[] {
if (isTextType(options.input)) {
return "";
} else {
return [];
}
}
// const result1: string
const result1 = foo("", { placeholder: "", entries: [], input: "text" });
// const result2: string[]
const result2 = foo("", { placeholder: "", entries: [], input: "radio" });
This is easy to read and understand for simple cases like yours, but if you have many such arguments then it could get a little tedious to write out all the possible overloads.