❌ Don't Do like this
// paragraph.tsx
export type Props = {
text: string;
}const Paragraph = ({text}: Props) => <p>{text}</p>// title.tsx
// Title is now tightly coupled to paragraph.txs > Props
import {Props} from './paragraph' const Title = ({text}: Props) => <h1>{text}</h1>
✅ Better Way
// models.ts
export interface User {
name: string,
age: number;
};
// user-profile.tsx
import {User} from './models';
type Props = {
user: User,
date: string, // other props
};
const UserProfile = ({user, date}: Props) => ...
export default UserProfile;
// user-list.tsx
import {User} from './models';
type Props = {
users: User[],
};
const UserList = ({users}: Props) => ...
export default UserList;
// type-helpers.ts
import * as React from "react";
export type GetComponentProps<T> = T extends
| React.ComponentType<infer P>
| React.Component<infer P>
? P
: never;
// title.tsx
type Color = "RED" | "BLUE" | "GREEN";
type Props = {
title: string;
color: Color;
};
const Title = ({ title, color }: Props) => (
<h1 style={{ color }}>{title}</h1>
);
export default Title;
// title-wrapper.tsx
import Title from './title';
type Props = GetComponentProps<typeof Title> & {
onClick: () => void;
};
const TitleWrapper = ({onClick, ...rest}: Props) => (
<div onClick={onClick}>
<Title {...rest} />
</div>
);
export default TitleWrapper;
// index.ts
import TitleWrapper from 'title-wrapper';
// Full type safety and autocompletion! 🎉
const App = () => (
<TitleWrapper
title="Hello there"
color="GREEN"
onClick={() => window.alert("title pressed")}
/>
);