TypeScript Version: 2.3.1
Code
With the above mentioned version I can't spread Props objects anymore to child React components, when the Props don't match up 100%.
/* App.tsx */
interface Props {
...
scopes: any;
}
interface State {}
export class App extends React.Component<Props, State> {
render() {
return <Content {...this.props} />; // error
}
}
/* Content.tsx */
interface Props {
...
// without scopes in Props
}
export default class Content extends React.Component<Props, {}>{
...
}
Expected behavior:
No error and there wasn't any on 2.2.1
Actual behavior:
error:
ERROR in ./spa/js/comps/App.tsx
(121,49): error TS2322: Type '{ ui?: UIState; session?: SessionState; scopes?: any; users?: any; roles?: any; plugins?: any; us...' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Content> & Props & { children?: ReactNode; }'.
Property 'scopes' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Content> & Props & { children?: ReactNode; }'.
You can do like below, but may get a warning about scopes being unused.
export class App extends React.Component<Props, State> {
render() {
const { scopes, ...otherProps } = this.props;
return <Content {...otherProps} />;
}
}
The same question. It's hard to understand why the following code will not compile anymore in v2.3
import * as React from "react";
interface ComponentProps {
property1: string;
property2: number;
}
export default function Component(props: ComponentProps) {
return (
<AnotherComponent {...props} />
);
}
interface AnotherComponentProps {
property1: string;
}
function AnotherComponent({ property1 }: AnotherComponentProps) {
return (
<span>{property1}</span>
);
}
due to the error
Type '{ property1: string; property2: number; }' is not assignable to type 'IntrinsicAttributes & AnotherComponentProps'.
Property 'property2' does not exist on type 'IntrinsicAttributes & AnotherComponentProps'.
Btw, the same code without jsx will compile with no error
import * as React from "react";
interface ComponentProps {
property1: string;
property2: number;
}
export default function Component(props: ComponentProps) {
return React.createElement<AnotherComponentProps>(AnotherComponent, props);
}
interface AnotherComponentProps {
property1: string;
}
function AnotherComponent({ property1 }: AnotherComponentProps) {
return React.createElement("span", null, property1);
}
A little bit different but still the same.
export default class Panel extends React.Component<void, void> {
...
}
now leads to this error
TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Panel> & Readonly<{ children?: ReactN...'.
Type '{}' is not assignable to type 'void'.
Had to change void
to any, null or undefined
to make it work.
@luca-moser @luggage66 @etecture-plaube @pomadin The reason for change in behavior is that in 2.3, JSXAttributes
are type-check similar to object literal expression with freshness flag (this means that excess properties are not allowed) After discussing with @mhegazy, it is too restrictive and cases in examples here illustrate that. So we will make modification to the rule as follow:
If there exist JSX attributes that are specified explicitly such as <div classNames="hi" /> or
If there are only spread in JSX attributes such as <div {...this.props} />
excess properties will be allowed
I will get the PR up today and the fix should be in for tomorrow nightly if you would like to give that a try!
@yuit If you only allow the second case in your list, it will still break a lot of components. Parent components often spread their Props object further and compute some additional things which are passed explicitly.
Here's an example from my actual codebase:
this.props.users.sort((a, b) => a.name > b.name ? 1 : -1).forEach((user: User) => {
if (user._filtered) return;
users.push(<UserCard {...this.props} key={user.id} user={user}/>); // this would error out
});
@luca-moser Thanks for feed back! Here is the second thought :
I agreed with @luca-moser, it's common case to extend the props or to override some ones.
@yuit, the final solution looks acceptable as the 1st case (only explicitly attrs...) fits no jsx case.
interface Props {
p1: string;
}
function fn(props: Props) {
}
fn({ p1: "", p2: 1 }); // ERROR: Object literal may only specify known properties...
I also have a lot of Spread types may only be created from object types.
for { ...this.props }
in cases that worked well in 2.2.2,
For case <Component someProperty={this.privateMethod} />
I get 'privateMethod' is declared but never used.
. If I pass the property like <Component { ...{someProperty: this.privateMethod}} />
or make method public
, the error is gone
@IIIristraM could you share more repo for both cases. the Second may get fixed in the nightly. IF you could share a full repo, I can take a look
import { inject, observer } from 'mobx-react';
import * as React from 'react';
import { ProviderContext } from 'types';
interface IMapFunction<TInnerProps, TOuterProps> {
(context: ProviderContext, nextProps?: TOuterProps): TInnerProps;
}
export default <TInnerProps, TOuterProps>(mapStore: IMapFunction<TInnerProps, TOuterProps>) => (
(Component: React.ComponentClass<TInnerProps>) => {
const Observer = observer(Component);
@inject(mapStore)
class Connector extends React.Component<TInnerProps & TOuterProps, {}> {
public node: React.Component<TInnerProps, any>;
private setNode = (n: React.Component<TInnerProps, any>) => {
this.node = n;
}
public render() {
return <Observer { ...this.props } ref={this.setNode} />;
}
}
return Connector as React.ComponentClass<TOuterProps>;
}
);
both cases take place in this example
Where an error occur? Is it at here return <Observer { ...this.props } ref={this.setNode} />;
? can you share that class declaration if that is the case.
Yes, this is right code line.
Component
can be an any React component, observer(Component)
returns typeof Component
Definitions for React.Component
andobserver
are taken from definitely-typed repo.
@IIIristraM Thanks! I am able to see this error Spread types may only be created from object types
...this is consistent with how the spread type work in our system at the moment. Though I am talking with @sandersn @mhegazy later to see what we can do about that (we have this PR which we will discuss about ) we have others running into these (https://github.com/Microsoft/TypeScript/issues/14112#issuecomment-297802124)
@luca-moser @luggage66 @pomadin @etecture-plaube @IIIristraM We have fix for original in the master. It should be out for nightly tonight. Give that a try and let us know. We will have this fix for 2.3.3 as well.
@IIIristraM Note: the fix doesn't address " Spread types may only be created from object types" I will get that in another PR -> Update we have the fix into master nightly. Give it a try and let us know
@yuit I have compiled my code via build 2.4.0-dev.20170509, the error is gone. So I am waiting for v2.3.3 to move on.
@pomadin thanks for the feedbacks. We will have this fix in for 2.3.3
export function makeP<P>(Ctor: React.ComponentClass<P>): React.ComponentClass<P> {
return class extends React.PureComponent<P, void> {
public render(): JSX.Element {
return (
<Ctor {...this.props }/>
);
}
};
}
@yuit for 2.3.3-insiders.20170512
it still does not work (and for 2.4.0-dev.20170515
too).
@yuit please take a look
third time is a charm :). Please give typescript@next
a try tomorrow 5/16.
@mhegazy it works, thanks! Is there a chance to have this fix in 2.3.3 (or in next patch of 2.3)?
it should be in TS 2.3.3 later this week.
Having a similar issue @ Typescript 2.3.4
Type '{}' is not assignable to type 'Readonly<ISpinnerProps>'. Property 'showGlobalSpinner' is missing in type '{}
Component 1:
interface ISpinnerProps{
showGlobalSpinner: boolean
}
class SpinnerClass extends React.Component<ISpinnerProps, undefined> {
render() {
return (
// Some markup
)
}
}
export const Spinner = connect((state: State) => {
return {
showGlobalSpinner: selectors.showGlobalSpinner(state),
}
})(SpinnerClass)
Component 2:
interface IProps {
someOtherProp: string
}
class AppClass extends React.Component<IProps, undefined> {
render() {
return (
// Some markup
<Spinner/> // Error is thrown here.
)
}
}
export const App = connect(mapStateToProps, actionCreators)(AppClass)
This pattern to used to compile fine earlier.
Update: Please note that the example props in both of these components are passed via Redux.
showGlobalSpinner
is a required property of Spinner
. either set the property, or declare it as optional in ISpinnerProps
.
@mhegazy The problem is this showGlobalSpinner
prop is passed down by Redux connect. I think TS thinks that I'm handling passing these props via parent. I've updated the code example in my previous message.
I have the same problem as @levsthings, @mhegazy - the connect() method return type now seems to now require the props are set in the TSX when consuming the redux-connected component, whereas they are actually provided by react-redux
.
UPDATE: This appears to be more of a problem with the latest react + react-redux typings, rather than typescript 2.3.4, since I get similar errors with TS 2.2.2
If anyone is able to decipher the issue with the typings please let me know! Heres a link...
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-redux/index.d.ts
For now I'm just throwing 'as any' after connect(...) :smile:
This seems to be the breaking commit: https://github.com/DefinitelyTyped/DefinitelyTyped/commit/2bc7feeb48e5c79fac1d4a09b36b5ce8c80896af
Works in types/[email protected] and not in types/[email protected]
@giladaya You're correct, I've also confirmed that the entire problem stems from types/[email protected]
.
@dupski @giladaya @levsthings Can you comment on the PR? I think that's a better place for it than this issue since it's a different cause.
@levsthings this is also an issue when using mobx inject. Anyone have any insight on how to properly do this elegantly?
export function Stateless<P> (Component: typeof React.Component): React.StatelessComponent<P> {
const StateLessComponent: React.StatelessComponent<P> = props => (
<Component {...props}>
{props.children}
</Component>
)
return StateLessComponent
}
const CCol = Stateless<IColProps>(Col)
My editor not showing the error. But the compiler shows the error
app: (38,20): error TS2339: Property 'md' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes
Edit:
Now it fixed. with restart my app
Hi @pomadin , I met the same problem and then found the reason that is
you SHOULD pass value for those parameter in use.
For example:
If you delete "property1={'parents'} property2={'kids'}" the TS will notify error
I had the same issue which I resolved by extending JSX.IntrinsicAttributes
adding a data field to it:
interface JSXData<T> extends JSX.IntrinsicAttributes {
data : T;
}
const Row = (props: JSXData<BalanceEntry>) : JSX.Element => {
return (
<tr>
<td>
{props.data.name}
</td>
<td>
{props.data.nett}
</td>
<td>
{props.data.tax}
</td>
</tr>
);
}
class BalanceEntry {
name: string;
...
nett: number;
tax: number;
}
so I could render the table as follows:
render() {
let rows = this.data.map(entry => {
return <Row
key={entry.id}
data={entry}
/>
});
return (
<table className="table table-striped">
<thead>
<tr>
<th>Entry</th>
<th>Nett</th>
<th>Tax</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
);
}
Started using v 2.6.1 today and can still see a lot of errors similar to ones discussed here, i.e.
import * as React from "react";
import styled from "styled-components/native";
import { TouchableOpacity } from "react-native";
// -- types ----------------------------------------------------------------- //
export interface Props {
onPress: any;
src: any;
width: string;
height: string;
}
// -- styling --------------------------------------------------------------- //
const Icon = styled.Image`
width: ${(p: Props) => p.width};
height: ${(p: Props) => p.height};
`;
class TouchableIcon extends React.Component<Props> {
// -- default props ------------------------------------------------------- //
static defaultProps: Partial<Props> = {
src: null,
width: "20px",
height: "20px"
};
// -- render -------------------------------------------------------------- //
render() {
const { onPress, src, width, height, ...props } = this.props;
return (
<TouchableOpacity onPress={onPress} {...props}>
<Icon source={src} width={width} height={height} /> /* errors */
</TouchableOpacity>
);
}
}
export default TouchableIcon;
/* errors /*
-> i not assignable to type IntrinsincAttributes ...
this happens for all: src
width
an height
Started using v 2.6.1 today and can still see a lot of errors similar to ones discussed here, i.e.
I am not familiar with styled-components
, but seems like you have Props
requiring src
and onPress
. and that is the err you are getting.. the error is not about src
, width
and height
, it is about missing properties.
I just added react-router-dom to a https://github.com/wmonk/create-react-app-typescript app and added the following code and got a similar error:
any ideas?
@QuantumInformation use RouteComponentProps from 'react-router'
in your Home component
export class Home extends React.Component<RouteComponentProps<void>, any>
I'm using ConnectedRouter now and it just works, even with just:
const Home = () => (
<div>
<h2>Home</h2>
</div>
)
I'm also having issues with this
interface RoleProps {
radius?: number;
size?: "small" | "medium" | "big";
look?: "primary" | "secondary" | "dark" | "light";
}
export class Button extends React.PureComponent<RoleProps> {
render() {
return (
<InternalButton {...this.props} > {this.props.children} </InternalButton>
)
}
}
// InternalButton has P = <RoleProps & Themer>
error TS2322: Type '{ children: ReactNode[]; radius?: number | undefined; size?: "big" | "small" | "medium" | undefin...' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick<RoleProps & Themer, "radius" | "siz...'.
Type '{ children: ReactNode[]; radius?: number | undefined; size?: "big" | "small" | "medium" | undefin...' is not assignable to type 'Readonly<Pick<RoleProps & Themer, "radius" | "size" | "look"> & HTMLProps<HTMLButtonElement> & Ex...'.
Types of property 'size' are incompatible.
Type '"big" | "small" | "medium" | undefined' is not assignable to type '(undefined & number) | ("big" & undefined) | ("big" & number) | ("small" & undefined) | ("small" ...'.
Type '"big"' is not assignable to type '(undefined & number) | ("big" & undefined) | ("big" & number) | ("small" & undefined) | ("small" ...'.
That should technically work as the common props should spread.
Honestly, I just started using Typescript in a React project, and I've spent most of my time dealing with issues like this. It's a shame.
@kevinSuttle can you file a new issue? This is labelled fixed. In case it's not fixed, can you explain how the error reproduces in your code?
@sandersn Is this not sufficient enough for you https://github.com/Microsoft/TypeScript/issues/15463#issuecomment-353257033 ?
@seivan What is the type of Themer? The intersection of RoleProps & Themer is too big to print in an error message, it looks like.
@levsthings @mhegazy @sandersn Hey guys I am also stuck on this, been bashing my head all week.
I am new to react, redux and typescript and I have been following the SPA template for React and Redux in VS2017.
I keep getting this error:
ERROR in [at-loader] ./ClientApp/components/Layout.tsx:9:15
TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes& Readonly<{ children?: ReactNode; }>...'.
Type '{}' is not assignable to type 'Readonly'.
Property 'isLoading' is missing in type '{}'.
import * as React from 'react';
import { Link } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap';
import { Nav } from 'react-bootstrap';
import * as SportsState from '../store/Sport';
import { RouteComponentProps } from 'react-router';
import { ApplicationState } from '../store';
import { connect } from 'react-redux';
// At runtime, Redux will merge together...
type SportProps =
SportsState.SportsState // ... state we've requested from the Redux store
& typeof SportsState.actionCreators // ... plus action creators we've requested
& RouteComponentProps<{}>;
export class NavScroller extends React.Component<SportProps> {
componentWillMount() {
// This method runs when the component is first added to the page
//this.props.requestSports();
}
public render() {
return <div className="nav-scroller bg-white box-shadow mb-4">
<Nav className="nav nav-underline" >
{this.props.sports && this.props.sports.map(sport =>
<Link className='nav-link' to={`/Sport/${sport.id}`}>
<img src={`../images/icons/${sport.name}.svg`}/>{sport.name}
</Link>
)}
</Nav>
</div>
}
}
export default connect(
(state: ApplicationState) => state.sports, // Selects which state properties are merged into the component's props
SportsState.actionCreators // Selects which action creators are merged into the component's props
)(NavScroller) as any;
import * as React from 'react';
import { NavMenu } from './NavMenu';
import { NavScroller } from './NavScroller';
export default class Layout extends React.Component<{}> {
public render() {
return <div>
<NavMenu />
<NavScroller/> <-----ERROR IS HERE
{this.props.children}
</div>;
};
}
Same here using React + Redux + Material-UI-Next. Seems those props are not injected properly.
In my case, withStyles should have injected classes
but I got Property 'classes' is missing in type '{ sample: SampleState; }'
import withStyles, { WithStyles } from 'material-ui/styles/withStyles';
type PropsWithStyle = Props & WithStyles<'root'>
// WithStyle introduces classes property
class Controller extends React.Component<PropsWithStyle , State> {}
export default withWidth()(withStyles(styles)(connect(mapStateToProp)(SampleComponent)));
Hey guys I got the same problem too,please help me
<Button label="Force Update" onClick={() => {
// this.setState({splits});
setInterval(() => {
let width = this.state.width - 10;
this.setState({width});
}, 100);
}}></Button>
Type '{ label: "Force Update"; onClick: () => void; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Button> & Readonly<{children?: ReactNode; }> & Re...'.
Type '{ label: "Force Update"; onClick: () => void; }' is not assignable to type 'Readonly<{ icon: Element; label?: string; title?: string; isDisabled?: boolean; onClick?: Functio...'.
Property 'icon' is missing in type '{ label: "Force Update"; onClick: () => void; }'.
ERROR in [at-loader] ./src/util.ts:81:19
@ILL35T NavScroller
extends React.Component<SportProps>
so when rendering it you need to pass SportProps
as its props, but you are not passing it any props and that is the reason for the error. If the props are optional then they need to be marked as such with ? or if you want to make them all optional then maybe extend React.Component<Partial<SportProps>>
@nileshgulia1 Property 'icon' is missing in type '{ label: "Force Update"; onClick: () => void; }'
you need to either pass Button an 'icon' prop or mark it as optional on the ButtonProps interface.
@sandersn Sorry to get back to you so late.
I made it simple for testing, it's just
export interface Themer {
theme: { color: string }
}
What I am trying to figure out that is ambiguous and unclear (a failure I attribute to TypeScript or at least its documentation) is out the spread operator works overall.
Perhaps you could help clear that up here, and we could take a look at the documentation to make it less ambiguous.
https://github.com/Microsoft/TypeScript/issues/15463#issuecomment-353257033
This seems like a bug (but obviously I could be wrong)
Pick<RoleProps & Themer, "radius" | "size" | "look">
If we're picking properties then Themer
should be irrelevant.
I am having same issue but only when I saperate out component and containers!
Really fustrating :|
Yes, I too am having the issue. If you pull in a container that gets its properties from a redux store, you cannot compile without specifying the properties. An example is it seems to occur with typescript and when you cast the connect back to the base type
connect((state: ApplicationState) => state.myState, actionCreators)(MyList) as typeof MyList;
If I do this to create a container and then use it in a page like this
import * as React from 'react';
import MyList from './MyList'
class MyPage extends React.Component {
render() {
return <MyList />; // <--- I will get the error here
}
}
export default MyPage ;
If I leave off the 'as typeof MyList' in the connect of the container then the error goes away. However I lose being able to have type on the container
I'm also having this exact same issue and I've spent the better part of the day scouring the internet trying to find what's wrong since this issue doesn't have an update. I've tried following different tutorials on different ways to connect redux with react.
For the ~16 hours I've spent today on this I'm coming to the conclusion that React + Redux + TS doesn't work.
Typescript: 2.7.2
Sample:
(10,16): Property 'createBook' does not exist on type 'Readonly<{ children?: ReactNode; }> & Readonly<{}>'.
With this simple:
import React from 'react';
import { connect } from 'react-redux';
class Book extends React.Component {
constructor(props: any){
super(props);
}
submitBook(input: any){
this.props.createBook(input);
}
render(){
let titleInput;
return(
<div>
<h3>Books</h3>
<ul>
{this.props.books.map((b, i) => <li key={i}>{b.title}</li> )}
</ul>
<div>
<h3>Books Form</h3>
<form onSubmit={e => {
e.preventDefault();
var input = {title: titleInput.value};
this.submitBook(input);
e.target.reset();
}}>
<input type="text" name="title" ref={node => titleInput = node}/>
<input type="submit" />
</form>
</div>
</div>
)
}
}
// Maps state from store to props
const mapStateToProps = (state, ownProps) => {
return {
// You can now say this.props.books
books: state.books
}
};
// Maps actions to props
const mapDispatchToProps = (dispatch) => {
return {
// You can now say this.props.createBook
createBook: book => dispatch({
type: 'ADD_BOOK',
id: book.id
})
}
};
// Use connect to put them together
export default connect(mapStateToProps, mapDispatchToProps)(Book);
:arrow_up: One of a bunch of different ways I've tried.
@mechanic22 It's not perfect, but I just did return React.createElement(MyList);
to solve this.
@tsteuwer you should let Book
to know that would be it's props. that connected components will be exported, but not-connected-raw-Book
component don't know it's type of Props
so if you do this
interface IBook {}
interface Props {
books: IBook[],
createBook: (book: IBook) => void
}
class Book extends React.Component<Props> {
...
}
then it will be ok
@levsthings I got the same issue, but I don't see any solution apart from what @PaitoAnderson suggested (return React.createElement(MyList);
-- that worked). So what about a proper way?
This issue is the reason I'm choosing Flow for my next project.
@Peterabsolon Flow will have its own set of problems and not give the same runtime guarantees as TS. But yeah, the compiler errors could use some more work :)
@seivan I looked at your example again and I noticed that InternalButton
wasn't defined, so I added an empty definition:
export class InternalButton extends React.Component<RoleProps & Themer> { }
expert class Button extends React.PureComponent<RoleProps> {
render() {
return <InternalButton {...this.props}></InternalButton>
The error I get is then "Property 'theme' is missing in '{ children: ReactNode[], radius?: number, size?: "small" ... }'." I can fix it by passing a theme
attribute to InternalButton, which makes sense because `InternalButton requires all the fields from both RoleProps and Themer:
return <InternalButton {...this.props} theme={{ color: 'brown' }}>{this.props.children}</InternalButton>
Note that I don't know React that well -- I'm just following the types, so I don't know if theme is actually required at runtime. As far as I can tell, the above is equivalent to the typescript function calls:
function InternalButton(props: RoleProps & Themer) { }
function Button(props: RoleProps) {
return InternalButton({ ...props, theme: { color: 'brown' } })
}
And for those definitions, it makes sense to me that theme
is required.
Most helpful comment
Honestly, I just started using Typescript in a React project, and I've spent most of my time dealing with issues like this. It's a shame.