Skip to content
This repository was archived by the owner on Dec 13, 2022. It is now read-only.

Commit 67ab5c4

Browse files
committed
Tricking TS to type-check component attributes
see microsoft/TypeScript#7004
1 parent e002f09 commit 67ab5c4

File tree

5 files changed

+44
-45
lines changed

5 files changed

+44
-45
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# babel-plugin-transform-ng1-jsx
22

3-
A proof of concept of type-checking Angular 1 templates with TypeScript.
3+
A proof of concept of type-checking Angular 1 templates with TypeScript.
44

5-
The idea is to use [JSX](https://facebook.github.io/jsx/) for the templates, to type-check them with TypeScript, and to convert them into the usual HTML string representation with a Babel plugin.
5+
The idea is to use [JSX](https://facebook.github.io/jsx/) for the templates, to type-check them with TypeScript, and to convert them into the usual HTML string representation with a Babel plugin.
66

77
The solution consists of two parts:
88

9-
1. Type definitions for JSX ([`ng1-jsx.d.ts`](ng1-jsx.d.ts))
9+
1. Type definitions for JSX ([`ng1-jsx.ts`](ng1-jsx.ts))
1010
2. The Babel plugin
1111

1212
Written in JSX, templates become just part of the TypeScript code. Include the type definitions with a `/// <reference path="..." />` comment, and use the [`--jsx preserve`](https://github.com/Microsoft/TypeScript/wiki/JSX) mode (`"jsx": "preserve"` in `tsconfig.json`) for the TypeScript compiler to understand and emit JSX. Finally, use the Babel plugin to compile JSX into HTML strings.
@@ -52,8 +52,6 @@ You can find an example to play with in the `example` folder. Run `npm run build
5252

5353
# Issues / TBD
5454

55-
* Type-checking component attributes. This one currently is **a big show stopper**. TypeScript _almost_ (but not quite) allows this. See the comments in [`ng1-jsx.d.ts`](ng1-jsx.d.ts).
56-
5755
* Non-JS syntax elements in Angular expressions: filters and one-time bindings.
5856

5957
The comma operator can help with this: `attr={ '|myFilter', $ctrl.foo }`, `ng-if={ '::', $ctrl.flag }`. This seems to be a good solution for one-time bindings, however the filters can change the type of the resulting value, so it's not type-checkable.
@@ -71,4 +69,5 @@ You can find an example to play with in the `example` folder. Run `npm run build
7169
* [JSX in TypeScript](https://github.com/Microsoft/TypeScript/wiki/JSX)
7270
* [Angular Expressions](https://docs.angularjs.org/guide/expression)
7371
* [TypeScript, issue #5151: checking frontend template files](https://github.com/Microsoft/TypeScript/issues/5151)
72+
* [TypeScript, issue #7004: JSX: a way to make all the properties of value-based elements optional](https://github.com/Microsoft/TypeScript/issues/7004)
7473
* [Refactoring Angular Apps to Component Style](http://teropa.info/blog/2015/10/18/refactoring-angular-apps-to-components.html)

example/src/example.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
/// <reference path="../../ng1-jsx.d.ts" />
1+
/// <reference path="../../ng1-jsx.ts" />
22

33
var mod = angular.module('example', []);
44

5-
6-
class ParentView {
5+
class ParentView extends Component {
76
record: { id: string };
87
flag: boolean;
9-
save(data: string) { }
8+
save(data: string) {}
109
}
1110

1211
mod.component('parentView', {
@@ -21,19 +20,24 @@ mod.component('parentView', {
2120
mod.factory('parentViewTemplate', function() {
2221
let $ctrl: ParentView;
2322
return (
24-
<div class='ooo'>
25-
{ $ctrl.record.id }
26-
<ChildView someParameter="aaa" onSave={ ({data}) => $ctrl.save(data) } />
27-
<span ng-if={ $ctrl.flag }>foo</span>
23+
<div class="ooo">
24+
{$ctrl.record.id}
25+
<ChildView
26+
someParameter="aaa"
27+
onSave={({ data }) => $ctrl.save(data)}
28+
/>
29+
<span ng-if={$ctrl.flag}>foo</span>
2830
</div>
2931
);
3032
});
3133

32-
33-
class ChildView {
34+
class ChildView extends Component {
3435
someParameter: string;
3536
onSave: (param: { data: string }) => void;
36-
// doSave() { this.onSave({data: 'abc'}); }
37+
doSave() {
38+
var a = { a: 1 };
39+
this.onSave({ data: 'abc' });
40+
}
3741
}
3842

3943
mod.component('childView', {
@@ -43,7 +47,7 @@ mod.component('childView', {
4347
someParameter: '<',
4448
onSave: '&'
4549
}
46-
})
50+
});
4751

4852
mod.factory('childViewTemplate', function() {
4953
let $ctrl: ChildView;

example/tsconfig.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@
33
"jsx": "preserve",
44
"experimentalDecorators": true
55
},
6-
"exclude": [
7-
"node_modules"
8-
]
6+
"exclude": ["node_modules"]
97
}

ng1-jsx.d.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

ng1-jsx.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
class Component {
2+
/** A bogus type-system-only property. */
3+
__bogusProps: Partial<this>;
4+
}
5+
6+
declare namespace JSX {
7+
interface IntrinsicElements {
8+
[elemName: string]: {
9+
class?: string;
10+
'ng-if'?: boolean;
11+
'ng-show'?: boolean;
12+
'ng-hide'?: boolean;
13+
'ng-class'?: { [key: string]: string };
14+
// and so on
15+
};
16+
}
17+
18+
type Element = string;
19+
20+
interface ElementAttributesProperty {
21+
__bogusProps: any;
22+
}
23+
}

0 commit comments

Comments
 (0)