Since the new unknown
type was added, it makes sense to replace a lot (if not all) usage of any
in the definition files with unknown
. For example:
Array.isArray(a: unknown): a is unknown[];
JSON.parse(a: string): unknown;
However, this change will cause many errors in projects currently using the fact that the returned types are not type-checked. This means that the change could be controversial.
This is effectively the same proposal as strictAny
; see #24737
If it is true that any
has no use over unknown
except for compiler error suppression, I might make a script that replaces all usages for my own definition files.
This is effectively the same proposal as
strictAny
; see #24737
This is not exactly correct, the strictAny
flag proposal is a project-level compiler flag, whereas this is a proposal to make a change to the definition files to make them more exact.
It makes more sense for JSON.parse()
to return an unknown
in all cases rather than any
in all cases. #24737 makes a case that users need to know unknown
better, and I agree, this is a step in that direction.
Also, @ThomasdenH, I think you meant
Array.isArray(a: unknown): a is unknown[];
Yes, you're right!
I think the main hurdle here is potentially causing confusion when code breaks, but all code should be easy to fix. In the worst case scenario 'as any' will do.
For now you can override the types yourself and enjoy more strict type checks:
declare global {
interface JSON {
parse(text: string, reviver?: (key: any, value: any) => any): unknown;
}
interface ArrayConstructor {
isArray(a: unknown): a is unknown[];
}
interface Body {
json(): Promise<unknown>;
}
}
See also: #27265
Also, Array.isArray(a: unknown) a is unknown[]
wouldn’t break the following code or any other code which is using it on a union of types to determine if the argument is an array or not:
```ts
function foo(a: string | string[]) {
if (!Array.isArray(a)) {
a = [a];
}
return a.filter(s => !!s);
}
@mohsen1 Actually, that should be:
```ts
declare global {
interface JSON {
/* JSON doesn't support symbol keys, and number keys
* are coerced to strings, even in arrays */
/**
* Converts a JavaScript Object Notation (JSON) string into an object.
* @param text A valid JSON string.
* @param reviver A function that transforms the results. This function is called for each member of the object.
* If a member contains nested objects, the nested objects are transformed before the parent object is.
*/
parse(text: string, reviver?: (this: unknown, key: string, value: unknown) => unknown): unknown;
/**
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
* @param value A JavaScript value, usually an object or array, to be converted.
* @param replacer A function that transforms the results.
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
*/
stringify(text: string, replacer?: (this: unknown, key: string, value: unknown) => unknown, space?: string | number): unknown;
}
interface ArrayConstructor {
isArray(a: unknown): a is unknown[];
}
interface Body {
json(): Promise<unknown>;
}
}
This is one of the biggest blind spots regarding type safety in big codebases. You can warn against using explicit any
with linting, but you can't change the types of all the declaration files
This change would be greatly appreciated: I'm trying to check data submitted by users which is supposed to be {foo: string}[]
and initially typed as unknown
.
As part of the checking process I'm calling Array.isArray
, which inconveniently types the data to any[]
, allowing code such as data[0].bar.baz.qux
to be written inside my type guard, which would throw a runtime error.
Currently a dirty workaround I'm using is creating a new var with the appropriate type after the isArray
check:
const typedData = data as unknown[];
@RyanCavanaugh now that you've backed off from strictAny, would you reconsider this? The original use case here (which motivated strictAny in the first place) would still be pretty valuable.
Just to note that Body.json()
during fetch should also return type Promise<unknown>
instead of Promise<any>
Most helpful comment
This is one of the biggest blind spots regarding type safety in big codebases. You can warn against using explicit
any
with linting, but you can't change the types of all the declaration files