TypeScript type for a string or array of strings
By Flavio Copes
Learn how to declare a TypeScript type that can be either a string or an array of strings using a union, written as string or string[].
Simple one, but I forgot the exact syntax and had to search for it, so let me write it:
export interface Props {
tag: string | string[]
}
tag can be a string, or an array of strings.
The | creates a union type: the property accepts either form. The same works with a type alias:
type Props = {
tag: string | string[]
}
I hit this writing an Astro component that takes either one tag or a list of tags. Both call sites should work, and with the union they do:
const one: Props = { tag: 'typescript' }
const many: Props = { tag: ['typescript', 'javascript'] }
Reading the value back
The union is convenient for callers, but it puts a small burden on the reading side. When you read tag, TypeScript only allows operations that exist on both types. Call an array method directly and it complains:
Property 'map' does not exist on type 'string | string[]'.
Property 'map' does not exist on type 'string'.
The fix is to narrow with Array.isArray(), which is the runtime check TypeScript understands for arrays:
function normalizeTags(tag: string | string[]) {
return Array.isArray(tag) ? tag : [tag]
}
When the check is true, tag is a string[] and is returned as-is. When it is false, tag must be a string, so wrapping it in brackets produces an array. The return type is inferred as string[] without any annotation.
This is the pattern I recommend: accept two convenient input shapes at the boundary, then normalize them immediately. Call normalizeTags() once, and the rest of the component works with a plain string[] — no repeated Array.isArray() checks scattered through the code.
The same union works anywhere, not just in component props. A function parameter typed string | string[] gives callers the same flexibility, with the same one-line normalization inside.
Exercise: reject an array containing a number, then hover over the result of normalizeTags('typescript').
Related posts about typescript: