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

react-native typings not work since typescript 3.1.1 #27421

Open
vovkasm opened this Issue Sep 28, 2018 · 2 comments

Comments

Projects
None yet
4 participants
@vovkasm

vovkasm commented Sep 28, 2018

TypeScript Version: 3.2.0-dev.20180927

Search Terms: react-native, stylesheet

Code
I'm created repo to reproduce:

  1. git clone https://github.com/vovkasm/rn-ts-3.1.1.git
  2. cd rn-ts-3.1.1
  3. npm 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:

  1. It works with ts 3.0.3
  2. 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)
  3. I traced type definitions of react-native.d.ts and they appears to be correct (again, from my point of view)...
@mattmccutchen

This comment has been minimized.

Show comment
Hide comment
@mattmccutchen

mattmccutchen Sep 29, 2018

Contributor

I don't understand what's going on in the type inference on the call to StyleSheet.create. Somehow including both fontWeight and marginTop is causing it to behave in a way the @types/react-native authors didn't intend so that the type of the fontWeight property gets widened to string.

The rest I do understand: after the StyleSheet.create call, s.didNotWork is a RegisteredStyle<T> object where T is a type that is incompatible with TextStyle because the fontWeight got widened. This RegisteredStyle<T> was assignable to an unregistered TextStyle in 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 (as RegisteredStyle<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).

Contributor

mattmccutchen commented Sep 29, 2018

I don't understand what's going on in the type inference on the call to StyleSheet.create. Somehow including both fontWeight and marginTop is causing it to behave in a way the @types/react-native authors didn't intend so that the type of the fontWeight property gets widened to string.

The rest I do understand: after the StyleSheet.create call, s.didNotWork is a RegisteredStyle<T> object where T is a type that is incompatible with TextStyle because the fontWeight got widened. This RegisteredStyle<T> was assignable to an unregistered TextStyle in 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 (as RegisteredStyle<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

This comment has been minimized.

Show comment
Hide comment
@mattmccutchen

mattmccutchen Sep 29, 2018

Contributor

Reduced example (same behavior in 3.0.3 and 3.2.0-dev.20180927):

interface TextStyle extends ViewStyle {
  fontWeight?: "900";
}
interface ViewStyle {
  marginTop?: number;
}

declare function create<T extends { [P in keyof T]: TextStyle | ViewStyle }>(styles: T): T;
const s = create({
  didNotWork: {
    fontWeight: '900', // if we comment this line, errors gone
    marginTop: 5, // if this line commented, errors also gone
  },
});
const f1: TextStyle = s.didNotWork;
Contributor

mattmccutchen commented Sep 29, 2018

Reduced example (same behavior in 3.0.3 and 3.2.0-dev.20180927):

interface TextStyle extends ViewStyle {
  fontWeight?: "900";
}
interface ViewStyle {
  marginTop?: number;
}

declare function create<T extends { [P in keyof T]: TextStyle | ViewStyle }>(styles: T): T;
const s = create({
  didNotWork: {
    fontWeight: '900', // if we comment this line, errors gone
    marginTop: 5, // if this line commented, errors also gone
  },
});
const f1: TextStyle = s.didNotWork;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment