Repository navigation
react-native typings not work since typescript 3.1.1 #27421
Copy link
Copy link
Closed
Labels
Working as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
Description
TypeScript Version: 3.2.0-dev.20180927
Search Terms: react-native, stylesheet
Code
I'm created repo to reproduce:
git clone https://github.com/vovkasm/rn-ts-3.1.1.gitcd rn-ts-3.1.1npm install && npm test
Paste here for easy reading
import React from 'react'
import { StyleSheet, Text } from 'react-native'
const s = StyleSheet.create({
didNotWork: {
fontSize: 16,
fontWeight: '900', // if we comment this line, errors gone
marginTop: 5, // if this line commented, errors also gone
},
work: {
fontSize: 18,
// fontWeight: '900', // when uncommented also work
},
})
export const sample1 = <Text style={s.work} />
export const sample2 = <Text style={s.didNotWork} />
// ^ this line generate error:
// index.tsx:17:30 - error TS2322: Type 'RegisteredStyle<{ fontSize: number; fontWeight: string; marginTop: number; }>' is not assignable to type 'StyleProp<TextStyle>'.
// Type 'RegisteredStyle<{ fontSize: number; fontWeight: string; marginTop: number; }>' is not assignable to type 'RecursiveArray<false | TextStyle | RegisteredStyle<TextStyle> | null | undefined>'.
// Property 'length' is missing in type 'Number & { __registeredStyleBrand: { fontSize: number; fontWeight: string; marginTop: number; }; }'.
// 17 export const sample2 = <Text style={s.didNotWork} />
// ~~~~~
// node_modules/@types/react-native/index.d.ts:907:5
// 907 style?: StyleProp<TextStyle>;
// ~~~~~
// The expected type comes from property 'style' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<Text> & Readonly<{ children?: ReactNode; }> & Readonly<TextProps>'
export const sample3 = <Text style={{fontSize: 16, fontWeight: '900', marginTop: 5}} />Expected behavior:
No errors
Actual behavior:
An error occured:
index.tsx:17:30 - error TS2322: Type 'RegisteredStyle<{ fontSize: number; fontWeight: string; marginTop: number; }>' is not assignable to type 'StyleProp<TextStyle>'.
Type 'RegisteredStyle<{ fontSize: number; fontWeight: string; marginTop: number; }>' is not assignable to type 'RecursiveArray<false | TextStyle | RegisteredStyle<TextStyle> | null | undefined>'.
Property 'length' is missing in type 'Number & { __registeredStyleBrand: { fontSize: number; fontWeight: string; marginTop: number; }; }'.
17 export const sample2 = <Text style={s.didNotWork} />
~~~~~
node_modules/@types/react-native/index.d.ts:907:5
907 style?: StyleProp<TextStyle>;
~~~~~
The expected type comes from property 'style' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<Text> & Readonly<{ children?: ReactNode; }> & Readonly<TextProps>'
Playground Link: https://github.com/vovkasm/rn-ts-3.1.1
Related Issues: no
Sorry, I can't found a way to reduce this regression farther to smallest possible example. But it looks like this actually typescript regression because:
- It works with ts 3.0.3
- It magically (from my point of view) will pass test if we change code in unrelated parts (comment/uncomment some styles - see comments in index.tsx)
- I traced type definitions of react-native.d.ts and they appears to be correct (again, from my point of view)...
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Working as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
Activity
mattmccutchen commentedon Sep 29, 2018
I don't understand what's going on in the type inference on the call to
StyleSheet.create. Somehow including bothfontWeightandmarginTopis causing it to behave in a way the@types/react-nativeauthors didn't intend so that the type of thefontWeightproperty gets widened tostring.The rest I do understand: after the
StyleSheet.createcall,s.didNotWorkis aRegisteredStyle<T>object whereTis a type that is incompatible withTextStylebecause thefontWeightgot widened. ThisRegisteredStyle<T>was assignable to an unregisteredTextStylein TypeScript 3.0.3, but it no longer is because of #26790, which changed the weak type assignability check to apply when the source is a primitive type (asRegisteredStyle<T>is). #26790 was described as an "optimization" and appears to be more than that, but the change still seems reasonable to me, so I believe the fix will have to be elsewhere (in TypeScript or@types/react-native).mattmccutchen commentedon Sep 29, 2018
Reduced example (same behavior in 3.0.3 and 3.2.0-dev.20180927):
ahejlsberg commentedon Oct 18, 2018
This is working as intended, but it's subtle to say the least. I'm going to describe what happens using the reduced example posted by Matt McCutchen (@mattmccutchen) above.
First, because the constraint for
Tis written in terms ofTitself and we can't simultaneously depend onTand infer forT, we end up having no contextual type for thestyles: Tparameter. Therefore, we inferstringandnumberinstead of literal types for thefontWeightandmarginTopproperties. So, we end up with{ didNotWork: { fontWeight: string, marginTop: number } }as the inference forT.We then check for assignability to the instantiated constraint, i.e.
{ didNotWork: TextStyle | ViewStyle }. This check ends up succeeding because the inferred type is assignable toViewStyle. However, the inferred type is not assignable toTextStyleso we get an error in the declaration off1.If you comment out
fontWeight: '900'we proceed the same way as above and get the same error. However, if you comment outmarginTop: 5we now fail the constraint check during inference forTand default to the constraint itself, i.e.{ fontWeight: TextStyle | ViewStyle }. We subsequently pass the signature applicability check because now the object literal has a contextual type with literal types in it.As I said, it's subtle!
I'd suggest changing the constraint for
Tto use a string index signature:With that change it works as expected because everything gets properly contextually typed.
vovkasm commentedon Oct 19, 2018
Anders Hejlsberg (@ahejlsberg)
Sorry for disturb, but I need some clarification. I think I understand what was written. But then I supposed that this fix should not detect errors when we use not existing keys on T (because T extends generic object that can have any property
[x: string]: TextStyle | ViewStyle).I modified reduced example to check this:
It is good that last line emit error in context of recommended fix. But isn't it counter intuitive? I don't understand this.
fiznool commentedon Oct 19, 2018
If the behaviour is as expected, is it reasonable to assume that the React Native typings need to be updated to eliminate this discrepancy?
Until this is fixed I guess the workaround is to use TS 3.0.3 if you want to use
@types/react-native?mattmccutchen commentedon Oct 19, 2018
Here
Twould be an object literal type such as{didNotWork: {fontWeight: "900", marginTop: number}}, which has no index signature, so trying to access a nonexistent property generates an error. The syntaxT extends { [P: string]: TextStyle | ViewStyle }really just meansTis assignable to{ [P: string]: TextStyle | ViewStyle }. Arguably the word "extends" is a misnomer here given that the assignability relation supports several things that are not in the spirit of "extending", including (1) letting an object literal type be assignable to a type with an index signature (the relevant rule in our case) and (2) removing optional properties.vovkasm commentedon Oct 19, 2018
Matt McCutchen (@mattmccutchen) Thank you for explanation!
Then this definitely can be fixed on typings side :-)
vovkasm commentedon Oct 19, 2018
Can I close this issue now? It seems no work can be done on this side...
mattmccutchen commentedon Oct 19, 2018
Yes please. Otherwise, the TypeScript team has an automated process that will eventually close it based on the "Working as Intended" label.
ScreamZ commentedon Oct 25, 2018
Vladimir Timofeev (@vovkasm) So what now ?
vovkasm commentedon Oct 25, 2018
Andréas Hanss (@ScreamZ) I don't know... most probably we will not be able express such types reliable until typescript 10 or 20 :-/
Changes suggested by typescript team simple did not work...
ScreamZ commentedon Oct 25, 2018
Vladimir Timofeev (@vovkasm) GeekyAnts/NativeBase#2123 Looks like the same with native-base
ahejlsberg commentedon Oct 26, 2018
I see the fix to react-native got stalled with the fix I suggested (because it adds a new requirement for arguments to have a string index signature). Let me suggest a different fix. Change react-native's
StyleSheet.createfunction inindex.d.tsto have the following declaration:The
NamedStyles<any>part of the union type causes the constraint to have a string index signature (such that contextual types are provided), whereas theNamedStyles<T>part of the constraint ensures that a final inferred type without a string index signature is accepted.Best I can tell this fixes the issue and doesn't require any other changes.
sublimeye commentedon Nov 8, 2018
Anders Hejlsberg (@ahejlsberg) Could you provide an example of how exactly do you override
create?Fix react-native on TS 3.1+
attilah commentedon Nov 17, 2018
In the same area of React Native I found a similar error, after the fix was applied and I think it can be a TypeScript error. I've extracted the relevant parts so the repro with the latest TSC is easy.
Code:
After calling TSC test.ts, this is the error:
overflowdefined in 2 different interfaces and I think that TS compiler fails early on mismatching valuesets because the interface types are not related, but one of them could be the result of thecreatemethod call.That is just the top of the cake that in React Native's case, FlexStyle has the overflow property, so an the ImageStyle interface which extends FlexStyle "overwrites" the valueset, but this time I separated it for clarity.