-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Replace any by unknown in definition files #26188
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
Comments
This is effectively the same proposal as |
If it is true that |
This is not exactly correct, the It makes more sense for |
Also, @ThomasdenH, I think you meant
|
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, function foo(a: string | string[]) {
if (!Array.isArray(a)) {
a = [a];
}
return a.filter(s => !!s);
} |
@mohsen1 Actually, that should be: 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: unknown, replacer?: (this: unknown, key: string, value: unknown) => unknown, space?: string | number): string;
}
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 |
This change would be greatly appreciated: I'm trying to check data submitted by users which is supposed to be As part of the checking process I'm calling Currently a dirty workaround I'm using is creating a new var with the appropriate type after the 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 |
@RyanCavanaugh I think this is a good proposal, and different from previous ones. One of the places where type safety is most important is when interacting with the outside world - when parsing JSON, making fetch requests, etc. Currently these are all typed as To be really type-safe, the return value in these cases should be For example, this code is currently valid: interface CatInfo {
age: number;
breed: string;
}
fetch("some-url").then(res => res.json()).then((cat: CatInfo) => {
// do something assuming the response is a cat
}) But in reality this could easily break. If the type returned by function isCatInfo(value: unknown): value is CatInfo {
// ...
}
fetch("some-url").then(res => res.json()).then((response) => {
if (isCatInfo(response)) {
// the type of response is now CatInfo
}
}) I'd love to see a way to at least opt-in to this kind of behavior, so we won't need to override the global type definitions (as in the example by @ExE-Boss) . |
I'm a bit confused. I don't see any case against |
I'd like to throw in my support for this proposal. Looks like it hasn't seen much attention lately. |
Typescript 5 would be a great time to introduce this. |
Fans of type-safety here at Beslogic would like this! I've been changing lots of types |
I wanted to express support for @lizraeli's response, since it's been a problem that we will eventually need to resolve in the code. As I was reading up to be able open this issue myself and saw this is already opened (several times #26993, #48697 but with different proposals). If you're already seasoned as a TS developer, you'll probably know that type TheType = { required: 'prop' }
function isTypeCorrect (v: unknown): v is TheType { ... }
const value = await (await fetch('something')).json()
if (isTypeCorrect(value)) {
// do things
} But, and I've seen this happen some times already (especially with someone that's starting in TS), is that the types are used like: type TheType = { required: 'prop' }
const value: TheType = await (await fetch('something')).json() And this is perfectly valid, it can also be true 99% of the times as well, but there's no indication or correct safeguard asserting that it is, which – at least for me – is a bit unsettling, especially if you're working in critical systems. My initial suggestion before the readup would be to make
That's also true, but this would be true for every case, and it's easier to pinpoint in a review when this is done, it's also easier to write an TSLint rule for this as well, but it's not that easy to figure out if the result from So I wanted to express the full support for this, especially saying that this is something widely used (we can see numbers in https://github.com/total-typescript/ts-reset where the users alone are 4.1k in GH and 172k downloads/month in npm) |
We really need to fix this. If it breaks code, isn't that the entire point of TypeScript? To not allow bad code? And it's not a big deal, because TS doesn't even do anything. Your exising JS will still work if your TS doesn't. We could even go a step further and use generics more and/or better types. For example, JSON.stringify shouldn't allow undefined or BigInts, but you could combine that with generics so that you can have a replacer argument getting rid of those values and then it would be allowed. |
@RyanCavanaugh Is there any update on this? It's been 5 years since this was labeled Awaiting more feedback. No arguments against it seem to have been provided, not even about "breaking change" and "not being able to opt out via a compiler option". This seems like a major and unnecessary source of unsoundness. Especially changing |
Would be great if this was considered for the next major version update 💞 |
I'm actually really bored of teaching less experienced people about this issue. It's a little embarrassing. I realise we have to be careful about breaking source compatibility but the migration of existing code is straightforward — mechanical, even. |
I'm surprised this hasn't been added as the default behavior. A |
Obligatory bump for support. 🫡 I strongly believe that typedefs for built-ins should not disable type safety, as it defeats the purpose of the language. |
I'm curious where the controversay would be? From what I've seen, people expect the return types to be type checked and are surprised when they learn that they are not. I actually think this is overall a good thing, it means people implicitly trust TypeScript to keep them safe from type errors. It's a huge miss when that isn't the case. Obviously this change would "break" a lot of existing projects because TypeScript would throw an error where it previously wouldn't. It therefore seems sensible to have a config option to enable the "strict" behavior. |
@davidbarratt There are a whooooole lot of silent happy users (who may or may not have bugs around I think everyone are in agreement that a compiler option that will be on by default on |
Since the new
unknown
type was added, it makes sense to replace a lot (if not all) usage ofany
in the definition files withunknown
. For example: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.
The text was updated successfully, but these errors were encountered: