Formerly titled âTurning ANY into UNKNOWNâ As a result of the change, 80-90% of ANY did not stay UNKNOWN, so the title was changed.
In TypeScript, there are two types of cases where âI used âanyâ because it was too much trouble to write the type properly even though I wrote the code myselfâ and âI used âanyâ because it was too much trouble to check the type of the value that comes from a third-party library. In the other case, I use âanyâ because I donât want to have to check the type of the value coming from a third party library.
For example, in the latter example, I was unsure of the type of the document object taken from Firestore, so I used any. ts
If we change this to UNKNOWN⊠ts
I donât know if UNKNOWN has EXISTS growing on it, he points out. I need to put a proper mold on it. ts
Iâll try to put an impossible type on it to get the necessary information. ts
Then a type compatibility error will show what type is expected.
Argument of type â(doc: number) â voidâ is not assignable to parameter of type â(value: DocumentSnapshot
) â void | PromiseLike â.
I found the name DocumentSnapshot<DocumentData>
, so I searched for it and found a reference
Itâs a long story, so I decided to give it an alias. ts
After this, I get another error. ts
It should not be undefined because I check its existence with doc.exists
and then get it with data = doc.data()
as Firestore explains, but TypeScript does not know that.
So we decide to throw an exception. ts
By doing this, the possibility of undefined in the flow after this point is eliminated, and TypeScript understands it properly.
By the way, I used to think âI shouldnât throw an exception if I can continue processing if I ignore it.â But after I started using Sentry, my thinking changed to âIf I throw an exception as soon as I detect a situation that shouldnât happen, I will be notified and can easily find the bug. I guess the fact that the exception on the userâs browser reaches the developer also influences the way I think about programming.
It was hard to change all the âanyâ to UNKNOWN at once. We should have done them one at a time. It makes it difficult to isolate complex problems when they arise.
- I got into React.forwardRef.
- If a function is used to wrap FC, declaring the type as âFCâ is not allowed, but if not declared, it is OK.
- Maybe forwardRef should be implemented to receive FCs.
In the end, we have to write the type properly because we canât use it as UNKNOWN, and UNKNOWN generally disappears. I thought the transition process was to change from any to unknown so that type checking would run, and then change the type to the appropriate type while watching the error content.
UNKNOWN was left with only one location.
onClick: () => unknown
- I havenât checked whether the return value is void or not, but since I donât use it, it doesnât matter either way, so it was decided to stay.
Iâll try to find the source code for a project I started writing years ago in ANY and process it. I wrote it while learning TypeScript, so there is quite a bit of ANY.
-
Day 1: 4 pomodoros, from 124 any to 56 any.
- Where ANY is often found
- Interaction with Firebase
- Thereâs no way for TypeScript to know what members doc.data() has.
- I was receiving MouseEvent, TouchEvent, etc. with any.
- I rewrite, âThis must be TouchEvent!â and when I rewrote it, I was told âI donât think TouchEvent has this memberâŠâ, grrrrrrrrrrrrrrrrâŠ
- I found out that the React definition of Touch doesnât have radiusX for this case.
- This is not standard, but is available in Safari on the iPad and I would like to use it.
- I found out that the React definition of Touch doesnât have radiusX for this case.
- Some places Paper.js wraps it and passes it around as a ToolEvent.
- There is an inconsistency in ToolEvent.event where it actually has a raw event, but the type says it doesnât.
- I rewrite, âThis must be TouchEvent!â and when I rewrote it, I was told âI donât think TouchEvent has this memberâŠâ, grrrrrrrrrrrrrrrrâŠ
- Interaction with Firebase
- In many cases, code written before I learned the technique of deliberately colliding types and reading the types given by the processor by mouse hovering is making any because I donât understand complex types.
- That kind of thing is easy because you can fix it right away.
- If the third-party code does not meet your expectations, you need to absorb the discrepancy somewhere, but the type check is invalidated at all possible locations of the value and its derivatives with any type, whereas with ts-ignore, it is invalidated at only one location, thus limiting the scope of the effect. This limits the scope of influence.
- Iâve hit what I think is a fundamentally bad design due to the lack of molds, and Iâm starting to feel that small changes wonât cut it unless I change the design from the ground up.
- Where ANY is often found
-
Day 2: Almost all gone
return (x as any).item ! == undefined;
should bereturn "item" in x;
- What is the type of component in React Router?
<Route path="/:id" component={MyComponent} />
- If you do
<Route path="/:id" component={1} />
,Type 'number' is not assignable to type 'FunctionComponent<any> | ComponentClass<any, any> | FunctionComponent<... ComponentClass<RouteComponentProps<any, StaticContext, PoorMansUnknown>, any> | FunctionComponent<... > | undefined'
, so itâs not helpful. - The correct answer is
const MyComponent: React.FC<RouteComponentProps<{ id: string }>>
.
- Firestore seems to get an error when trying to save a value containing undefined
{x: 1}
is OK,{x: 1, y: undefined}
is not.- TypeScript types cannot distinguish between the two.
- Type like
{ x: number; y: number | null }
, and if there is no y, do{ x: 1, y: null };
.
- We need to stop writing members with different types, such as
obj.foo = convertType(obj.foo)
.- To begin with, âan object with a different type and reinserted membersâ is a âdifferent objectâ and therefore has a different type, and trying to do this with a single variable makes it impossible to type the object.
new_obj = {...obj, foo: convertType(obj.foo)}
- It is also necessary to stop writing objects in such a way that they are completed by putting values into them in order.
- Bad ts
- Good
ts
- If you make any like the former, it's not checked if the object created by this function is really of type FOO.
- `e: paper.ToolEvent` really has `e.event`, but it is supposed to be absent on the type
- I used to write `const event = (e as any).event;`.
ts
- If you want to eliminate ANY, you can do it like this.
ts
- With a combination of these things, I rewrote the function that converts the state in the browser into an object that can be saved in Firestore as follows
- It's no good that position is a paper.Point object, so you can change it to `[number, number]` and so on.
- Extracting only the value to be stored or
- before
ts
- after
ts
- A function that takes a function and wraps it in a process and returns it, which is tricky
ts
- In order to do something about it, we needed generics.
ts
- I put in a bug that prevented me from reading historical data from Firestore.
- I assumed it was
isReadOnly: bool
, but there was only an entry when it was true.- [I was unknowingly clenching an exception.
- I assumed it was
- There were 124 anys and now there are 3.
- Two of them are the contents of a comment or message string
- The last one is a debug object type created for debugging convenience
- UNKNOWN has 16
- 80-90% of ANY turned into a decent type instead of turning into UNKNOWN.
Added 2021-02-18 Garbage cleanup for ANY Eraser Festival. - What you REQUIRE will be ANY - This caused an unacknowledged ANY in the code that uses Paper.js. - Fixed and paper.Item is now type-checked. - Spreading an instance of a class does not duplicate the method. - So I solved the problem with casts. Itâs not good to have casts all over the place, so we put them in one place. ts
This page is auto-translated from /nishio/2æ„æăăŠanyăæČæ» ăă using DeepL. If you looks something interesting but the auto-translated English is not good enough to understand it, feel free to let me know at @nishio_en. Iâm very happy to spread my thought to non-Japanese readers.