Issue
I'm trying to define a type that matches any object/dictionary but NOT arrays.
My first attempt didn't work since arrays are technically objects under the hood:
const a:{[k:string]: any} = []; // works fine
I also know that it's possible to create a generic "checker" like so:
type NoArray<T> = T extends any[] ? never : T;
But that's not what I'm looking for. I want a non-generic type that works like this:
const a: NoArrayType = {}; // works fine
const a: NoArrayType = []; // TypeError
Solution
Here's what I came up with, using a type intersection instead of an index signature:
/**
* Constrains a type to something other than an array.
*/
export type NotArray = (object | string | bigint | number | boolean) & { length?: never; };
This allows more than what the original poster was looking for, but it can easily be adjusted:
/**
* Constrains a type to an object other than an array.
*/
export type NonArrayObject = object & { length?: never; };
The advantage of not using an index signature is that you get an error if you access a property which doesn't exist:
function test(hello: NonArrayObject) {
return hello.world; // error
}
The disadvantages of using … & { length?: never; }
are that you can access the length
property of NotArray
, that you cannot use it for objects which happen to have a length
property, and that you cannot use it for functions because they have a length
property.
And if anyone is wondering, I use NotArray
to define optional return values, where in most cases only the first return value is of interest:
export type OptionalReturnValues2<T1 extends NotArray, T2> = T1 | [T1 | undefined, T2];
export function normalizeReturnValues2<T1 extends NotArray, T2>(optionalReturnValues: OptionalReturnValues2<T1, T2>): [T1 | undefined, T2 | undefined] {
if (Array.isArray(optionalReturnValues)) {
return optionalReturnValues;
} else {
return [optionalReturnValues, undefined];
}
}
export type OptionalReturnValues3<T1 extends NotArray, T2, T3> = T1 | [T1 | undefined, T2] | [T1 | undefined, T2 | undefined, T3];
export function normalizeReturnValues3<T1 extends NotArray, T2, T3>(optionalReturnValues: OptionalReturnValues3<T1, T2, T3>): [T1 | undefined, T2 | undefined, T3 | undefined] {
if (Array.isArray(optionalReturnValues)) {
return [optionalReturnValues[0], optionalReturnValues[1], optionalReturnValues[2]];
} else {
return [optionalReturnValues, undefined, undefined];
}
}
Answered By - Kaspar Etter
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.