Skip to content

feat: add typescript definitions #263

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ jobs:
- persist_to_workspace:
root: .
paths: .
lint-and-flow:
lint-and-typecheck:
<<: *defaults
steps:
- attach_workspace:
at: ~/linaria
- run: |
yarn lint
yarn flow
yarn typescript
unit-tests:
<<: *defaults
steps:
Expand Down Expand Up @@ -74,7 +75,7 @@ workflows:
build-and-test:
jobs:
- install-dependencies
- lint-and-flow:
- lint-and-typecheck:
requires:
- install-dependencies
- unit-tests:
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
"version": "1.0.0-alpha.13",
"description": "Blazing fast zero-runtime CSS in JS library",
"main": "lib/index.js",
"types": "types/index.d.ts",
"files": [
"lib/",
"types/",
"react.js",
"server.js",
"babel.js",
Expand All @@ -29,6 +31,7 @@
"scripts": {
"lint": "eslint .",
"flow": "flow",
"typescript": "dtslint types",
"test": "jest",
"test:unit": "jest __tests__",
"test:integration": "jest __integration-tests__",
Expand All @@ -50,12 +53,14 @@
"@babel/preset-flow": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@callstack/eslint-config": "^2.0.0",
"@types/react": "^16.4.18",
"all-contributors-cli": "^5.4.0",
"babel-core": "^7.0.0-bridge.0",
"codecov": "^3.1.0",
"conventional-changelog-cli": "^2.0.5",
"dedent": "^0.7.0",
"del-cli": "^1.1.0",
"dtslint": "^0.3.0",
"eslint": "^5.4.0",
"flow-bin": "^0.79.1",
"flow-copy-source": "^2.0.2",
Expand Down
5 changes: 3 additions & 2 deletions src/react/styled.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ type StyledComponent<T> = React.ComponentType<T & { as?: React$ElementType }>;

type StyledTag<T> = (strings: string[], ...exprs: Array<string | number | {} | (T => string | number)>) => StyledComponent<T>;

declare module.exports: {|
type StyledJSXIntrinsics = $ObjMap<$JSXIntrinsics, <T>({ props: T }) => StyledTag<T>>;

declare module.exports: StyledJSXIntrinsics & {|
<T>(T): StyledTag<React.ElementConfig<T>>,
[string]: StyledTag<{ children?: React.Node, [key: string]: any }>,
|};
*/
47 changes: 47 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// TypeScript Version: 2.8

declare module 'linaria' {
function css(
strings: TemplateStringsArray,
...exprs: Array<string | number | object>
): string;

function cx(
...classNames: Array<string | false | undefined | null | 0>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably be extracted into a separate type:

type FalseyValue = false | undefined | null | 0;

...classNames: (string | FalseyValue)[]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@resir014 yeah, I did that in a previous commit but then reverted, because it seems that all the type aliases I declare are exported. so the user could do:

import { cx, Falsy} from 'linaria'

Which feels wrong :(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, I see.

): string;
}

declare module 'linaria/react' {
import * as React from 'react';

type StyledComponent<T> = React.StatelessComponent<
T & { as?: React.ReactType }
>;

type StyledTag<T> = (
strings: TemplateStringsArray,
...exprs: Array<string | number | object | ((props: T) => string | number)>
) => StyledComponent<T>;

type StyledJSXIntrinsics = {
[P in keyof JSX.IntrinsicElements]: StyledTag<
JSX.IntrinsicElements[P] & { [key: string]: any }
>
};

const styled: StyledJSXIntrinsics & {
<T>(component: React.ReactType<T>): StyledTag<T>;

[key: string]: StyledTag<{
children?: React.ReactNode;
[key: string]: any;
}>;
};
}

declare module 'linaria/server' {
function collect(
html: string,
css: string
): { critical: string; other: string };
}
46 changes: 46 additions & 0 deletions types/tests/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { css, cx } from 'linaria';

const tomato = 'tomato';
const border = 1;

const absoluteFill = {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
};

// $ExpectType string
css`
color: ${tomato};
border-width: ${border}px;

&.abs {
${absoluteFill};
}
`;

// $ExpectType string
css`font-family: sans-serif`;

// $ExpectError
css`color: ${true}`;

// $ExpectError
css`color: ${undefined}`;

// $ExpectError
css`color: ${null}`;

// $ExpectType string
cx('test', false, undefined, null, 0);

// $ExpectError
cx('test', 42);

// $ExpectError
cx('test', true);

// $ExpectError
cx('test', {});
58 changes: 58 additions & 0 deletions types/tests/react.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';
import { styled } from 'linaria/react';

const white = 'white';
const tomato = 'tomato';
const border = 1;

const absoluteFill = {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
};

const Button = styled.button`
color: ${white};
background-color: ${props => props.background};
border-width: ${border}px;

&.abs {
${absoluteFill};
}
`;

const CustomButton = styled(Button)`
&:hover {
background-color: ${tomato};
}
`;

class Title extends React.Component<{ label: string; className?: string }> {
render() {
return <h1 className={this.props.className}>{this.props.label}</h1>;
}
}

const CustomTitle = styled(Title)`
font-family: sans-serif;
`;

// $Expect Element
<Button as="a">Hello world</Button>;

// $ExpectError
<Button onClick={42}>Hello world</Button>;

// $Expect Element
<CustomButton onClick={() => alert('Clicked')}>Hello world</CustomButton>;

// $Expect Element
<CustomTitle label="Hello world" />;

// $Expect Element
<CustomTitle label="Hello world" className="primary" />;

// $ExpectError
<CustomTitle />;
7 changes: 7 additions & 0 deletions types/tests/server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { collect } from 'linaria/server';

// $ExpectType { critical: string; other: string; }
collect(
'<div class="foo">Hello</div>',
'.foo { color: blue; }'
);
13 changes: 13 additions & 0 deletions types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": ["es6", "dom"],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react"
}
}
Loading