-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhance isObject
type Inference for function
and object
parameters
#257
Comments
isObject
type infer when passing a parameter with the type is function
or object
isObject
type Inference for function
and object
parameters
You can simplify the suggested fix to: export function isObject(value: unknown): value is Record<keyof any, unknown> {
return isTagged(value, '[object Object]')
} …and you would get the same effect. The only problem is that type Point = { x: number; y: number }
interface IDog {
bark(): void
}
interface StringToStringMap {
[key: string]: string
}
interface KeyToStringMap {
[key: keyof any]: string
}
declare const x: Record<string, string> | KeyToStringMap | StringToStringMap | IDog | Point | (() => void) | Function
if (isObject(x)) {
x // => Point | KeyToStringMap | Record<string, string>
} In the example above, you would expect |
I don't think So I guess the question is, what's the least worst solution? |
Here's my proposal: interface ObjectLike {
[key: string]: unknown
}
export function isObject<T = never>(value: unknown): value is T | ObjectLike {
return isTagged(value, '[object Object]')
} You can call it without a type parameter, and it will work for everything except type Point = { x: number; y: number }
interface IDog {
bark(): void
}
interface StringToStringMap {
[key: string]: string
}
interface KeyToStringMap {
[key: keyof any]: string
}
declare const x: Record<string, string> | KeyToStringMap | StringToStringMap | IDog | Point | (() => void) | Function | RegExp
if (isObject(x)) {
x // => Point | StringToStringMap | KeyToStringMap | Record<string, string>
} You can call it with a type parameter to ensure it works for such if (isObject<IDog>(x)) {
x // => IDog | Point | StringToStringMap | KeyToStringMap | Record<string, string>
} If if (isObject<IDog | ICat>(x)) {
x // => IDog | ICat | Point | StringToStringMap | KeyToStringMap | Record<string, string>
} |
Actually, I think we could get a complex conditional type to work without the need for explicit type parameters. It would need to rely on |
I didn't know about this limitation, good to know. And even better to know that there might be a solution, no matter how complex it is. I like your suggestion, it would already be good enough for now, given this limitation of some types having to be passed as generics. The only thing I would change is to make the generic extend from an export function isObject<T extends object = never>(value: unknown): value is T | ObjectLike {
return isTagged(value, '[object Object]')
} To block a weird thing like this: declare const x: Record<string, string> | KeyToStringMap | StringToStringMap | IDog | Point | (() => void) | Function | RegExp | string | number
if (isObject<number>(x)) {
x // => number | Point | StringToStringMap | KeyToStringMap | Record<string, string>
} else {
x // => string | number | Function | RegExp | IDog | (() => void)
} It would still allow this |
The types of the current code are wrong
See evidences
my suggestion to solve this
See results
when fixing this create the type tests for the function.
The text was updated successfully, but these errors were encountered: