Tuesday, October 17, 2017
Jest test fails after upgrading to React 16
Made it work by changing the shallow to mount:
Have to learn the difference of mount vs shallow.
Happy Coding!
Monday, October 16, 2017
ts-jest Cannot find name 'test'
There are two ways to fix that. One, import 'jest' directly:
Another way is to put the jest type in tsconfig.json:
Happy Coding!
Thursday, October 12, 2017
React 16 now allows rendering with no root element
This code:
render() { return ( <div> <h1>Hello world!</h1> <div>Welcome to hot-reloading React written in TypeScript! {this.state.count}</div> </div> ); }
Can now be rendered without the root element (e.g., div) in React 16:
Note the use of array above. This isn't allowed yet though:
Happy Coding!
render() { return ( <div> <h1>Hello world!</h1> <div>Welcome to hot-reloading React written in TypeScript! {this.state.count}</div> </div> ); }
Can now be rendered without the root element (e.g., div) in React 16:
render() { return ([ <h1>Hello world!</h1>, <div>Welcome to hot-reloading React written in TypeScript! {this.state.count}</div> ]); }
Note the use of array above. This isn't allowed yet though:
Happy Coding!
Monday, July 31, 2017
Redux combineReducers compiler error
If a Redux action is added with properties other than the type property, here it's payload..
..TypeScript will raise an error on combineReducers:
To fix the compilation error, make the Redux action property be optional:
Result:
However, TypeScript won't be able to catch missed properties, it won't raise an error that we didn't pass the payload property on User 6:
To fix that, remove the optional indicator on Redux action:
Result, TypeScript is now able to catch missed properties:
However, we are back to this error on combineReducers:
To comply with combineReducers requirement of Reducer actions containing just a type property only, create another interface that has optional properties (e.g., payload), and use that for the Redux reducer's action parameter (UserActionsNoPayload). And then on UserActions, inherit UserActionsNoPayload from UserActions:
Now, no more combineReducers compilation error, and the compiler is still able to catch missed properties:
Here are the TypeScript definitions for the routeToUser:
And here is how are the states and dispatchers are mapped as properties to a component via Redux's connect:
Happy Coding!
P.S.
At first, I tried creating UserActions with complete properties, and then made UserActionsNoPayload inherits UserActions and define payload as optional on UserActionsNoPayload; however, it's a compiler error:
export interface UserActions extends Action { type: UserKind; payload: UserPayload; }
..TypeScript will raise an error on combineReducers:
To fix the compilation error, make the Redux action property be optional:
export interface UserActions extends Action { type: UserKind; payload?: UserPayload; }
Result:
However, TypeScript won't be able to catch missed properties, it won't raise an error that we didn't pass the payload property on User 6:
To fix that, remove the optional indicator on Redux action:
export interface UserActions extends Action { type: UserKind; payload: UserPayload; }
Result, TypeScript is now able to catch missed properties:
However, we are back to this error on combineReducers:
To comply with combineReducers requirement of Reducer actions containing just a type property only, create another interface that has optional properties (e.g., payload), and use that for the Redux reducer's action parameter (UserActionsNoPayload). And then on UserActions, inherit UserActionsNoPayload from UserActions:
Now, no more combineReducers compilation error, and the compiler is still able to catch missed properties:
Here are the TypeScript definitions for the routeToUser:
export interface StateProps { user: Dto.Client.User; component: Component; counter: Dto.Client.Counter; } export interface ActionProps { routeToUser: UserDispatcher; doCounter: CounterDispatcher; } interface Props extends StateProps, ActionProps { } export type Dispatcher = (action: UserActions | CounterActions) => void; export type UserDispatcher = (action: UserActions) => void; export type CounterDispatcher = (action: CounterActions) => void; export default class ReduxFirstRouterApp extends React.Component<Props, {}> {
And here is how are the states and dispatchers are mapped as properties to a component via Redux's connect:
const mapStateToProps = ({user, component, counter}: StateProps) => ({user, component, counter}); const mapDispatchToProps = (dispatch: Dispatcher): ActionProps => ({ routeToUser: (action: UserActions) => dispatch(action), doCounter: (action: CounterActions) => dispatch(action) }); this.AppContainer = connect(mapStateToProps, mapDispatchToProps)(ReduxFirstRouterApp);
Happy Coding!
P.S.
At first, I tried creating UserActions with complete properties, and then made UserActionsNoPayload inherits UserActions and define payload as optional on UserActionsNoPayload; however, it's a compiler error:
Sunday, July 23, 2017
Inline destructuring
Found out a neat ES6 functionality, it can do destructuring of object right on parameters itself.
Below is how it is done on TypeScript:
Happy Coding!
Below is how it is done on TypeScript:
function greetNoDestructuring(dto: {name: string, favoriteNumber: number}): void { console.log(dto.name); console.log(dto.favoriteNumber); } function greetManualDestructuring(dto: {name: string, favoriteNumber: number}): void { const {name, favoriteNumber} = dto; console.log(name); console.log(favoriteNumber); } function greetInlineDestructuring({name, favoriteNumber}: {name: string, favoriteNumber: number}): void { console.log(name); console.log(favoriteNumber); } greetNoDestructuring({name: 'Kal', favoriteNumber: 7}); greetManualDestructuring({name: 'El', favoriteNumber: 6}); greetInlineDestructuring({name: 'Superman', favoriteNumber: 42});
Happy Coding!
redux-first-router 404
As with all client-side routing, when page is reloaded it will result to 404.
The easiest way to fix that is to indicate fallback page when 404 occurs, this is typically the index.html
On development environment that are using webpack-dev-server, just add the following:
devServer: { hot: true, proxy: { "/api": "http://localhost:3000" }, historyApiFallback: { index: "/index.html" } }
Aside from the above, on the fallback page indicate the base href:
<base href="/"/>
Happy Coding!
TypeScript + redux-first-router expected string class/function
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `App`
When that runtime error occurred, chances is the default is forgotten when importing Link since there is no TypeScript definition for redux-first-router-link yet.
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Provider, connect } from 'react-redux'; const Link = require('redux-first-router-link');
To fix:
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Provider, connect } from 'react-redux'; const Link = require('redux-first-router-link').default;
Happy coding!
Thursday, July 20, 2017
TypeScript can enforce code correctness is so awesome
TypeScript solves the industry's billion dollar mistake too
Reading about the advantage of Flow over TypeScript. Saw these slides:
With Flow, the error is caught at compile-time instead, which indeeds solves the billion dollar mistake:
TypeScript 2.0 already has the same functionality as Flow, it's just not the default. Just add "strictNullChecks": true to tsconfig.json.
With that settings, possible null/undefined errors can now be caught at compile-time:
If the type is explicitly added to the function it will complain that there is a path that could lead to undefined value:
Just include the undefined value in function's return type:
The inferred return type for function foo if return type is not included is string | undefined
Finally, to fix the undefined error:
Of course, if it can be guaranteed that a function returns a non-null/non-undefined value, no need to add undefined:
Happy Coding!
With Flow, the error is caught at compile-time instead, which indeeds solves the billion dollar mistake:
TypeScript 2.0 already has the same functionality as Flow, it's just not the default. Just add "strictNullChecks": true to tsconfig.json.
With that settings, possible null/undefined errors can now be caught at compile-time:
If the type is explicitly added to the function it will complain that there is a path that could lead to undefined value:
Just include the undefined value in function's return type:
The inferred return type for function foo if return type is not included is string | undefined
Finally, to fix the undefined error:
Of course, if it can be guaranteed that a function returns a non-null/non-undefined value, no need to add undefined:
Happy Coding!
Wednesday, June 14, 2017
GPG failed to write commit object
Got an error:
It took me more than two hours to narrow down the cause of the error:
These does not work too:
Error is caused by wrong configuration in gpg-agent.conf:
For some reasons the second line was added to the configuration:
That should just configured with this:
After correcting the configuration, gpg-agent is now working:
And so is gpg2:
With that, committing with gpg signing shall work, must configure gpg to use gpg2 if it is not yet configured to gpg2:
Happy Coding!
error: gpg failed to sign the data fatal: failed to write commit object
It took me more than two hours to narrow down the cause of the error:
These does not work too:
MacBook-Air:~ jack$ gpg2 --list-secret-keys gpg: can't connect to the agent: IPC connect call failed MacBook-Air:~ jack$ gpg-agent --daemon gpg-agent[1499]: /Users/jack/.gnupg/gpg-agent.conf:2: invalid option
Error is caused by wrong configuration in gpg-agent.conf:
$ cat ~/.gnupg/gpg-agent.conf
For some reasons the second line was added to the configuration:
pinentry-program /usr/local/bin/pinentry-mac /usr/local/bin/pinentry-mac
That should just configured with this:
pinentry-program /usr/local/bin/pinentry-mac
After correcting the configuration, gpg-agent is now working:
MacBook-Air:~ jack$ gpg-agent -v --daemon gpg-agent[2012]: listening on socket '/Users/jack/.gnupg/S.gpg-agent' gpg-agent[2012]: listening on socket '/Users/jack/.gnupg/S.gpg-agent.extra' gpg-agent[2012]: listening on socket '/Users/jack/.gnupg/S.gpg-agent.browser' gpg-agent[2012]: listening on socket '/Users/jack/.gnupg/S.gpg-agent.ssh' gpg-agent[2013]: gpg-agent (GnuPG) 2.1.21 started
And so is gpg2:
MacBook-Air:~ jack$ gpg2 --list-secret-keys gpg-agent[2013]: handler 0x70000e9d4000 for fd 7 started /Users/jack/.gnupg/pubring.gpg ------------------------------ sec rsa2048 2016-12-12 [SC]
With that, committing with gpg signing shall work, must configure gpg to use gpg2 if it is not yet configured to gpg2:
MacBook-Air:~ jack$ git config --global gpg.program gpg2
Happy Coding!
Monday, April 10, 2017
Tuples in TypeScript/ES6 and C# 7
TypeScript and ES6 has tuple functionality:
C# tuple is more flexible, as aside from that it allows destructuring the tuple to variables, it also supports returning the object as-is:
The named tuple can be easily achieved in TypeScript/ES6 by returning an object instead of array, however, the destructuring to variables using the array syntax won't work anymore:
Would have to use object destructuring syntax:
However, unlike in C#, that won't work in TypeScript/ES6. In TypeScript/ES6, we would have to match the name of the variables to the name of the object's property names that is being destructured from.
But if you really don't like the object's property names given by the author of the function, or it conflicts with your existing variable name; with TypeScript/ES6, you can rename the destructured variable using the following syntax:
Read more:
https://blogs.msdn.microsoft.com/typescript/2014/11/12/announcing-typescript-1-3/
https://strongloop.com/strongblog/getting-started-with-javascript-es6-destructuring/
http://wesbos.com/destructuring-renaming/
http://blog.marcgravell.com/2017/04/exploring-tuples-as-library-author.html
Happy Coding!
C# tuple is more flexible, as aside from that it allows destructuring the tuple to variables, it also supports returning the object as-is:
The named tuple can be easily achieved in TypeScript/ES6 by returning an object instead of array, however, the destructuring to variables using the array syntax won't work anymore:
Would have to use object destructuring syntax:
However, unlike in C#, that won't work in TypeScript/ES6. In TypeScript/ES6, we would have to match the name of the variables to the name of the object's property names that is being destructured from.
But if you really don't like the object's property names given by the author of the function, or it conflicts with your existing variable name; with TypeScript/ES6, you can rename the destructured variable using the following syntax:
Read more:
https://blogs.msdn.microsoft.com/typescript/2014/11/12/announcing-typescript-1-3/
https://strongloop.com/strongblog/getting-started-with-javascript-es6-destructuring/
http://wesbos.com/destructuring-renaming/
http://blog.marcgravell.com/2017/04/exploring-tuples-as-library-author.html
Happy Coding!
Tuesday, January 17, 2017
404 not found.
Got the error "Failed to decode downloaded font OTS parsing error: invalid version tag" and looks like the font can be read/decoded by the browser as the font can be previewed in the browser:
Making it seems that the reason why TinyMCE is not loading the fonts correctly..
..is due to incorrect mime type of text/html:
Although the font can be previewed by the browser, it looks like it is from previous successfully loaded font. Meaning, the browser aggressively caches the fonts, making it look like there is a very serious error, e.g., incorrect mime type of text/html when it should be application/woff, when in reality it is just a 404 that resulted to a 404 page(seemingly), yet without the status code of 404. A page is text/html.
The docker built just don't have font files in it.
Suggestions like nginx has missing mime types for the fonts, made the error looks complex than it really is.
404s are mostly a page, so that might be reason for the content type of text/html being reported by the browser. The browser might be returning a page, but it's hard to actually know since what the browser previews is the actual font, not a page. As for why the app is not returning status code of 404, would have to find out.
Happy Coding!
Making it seems that the reason why TinyMCE is not loading the fonts correctly..
..is due to incorrect mime type of text/html:
Although the font can be previewed by the browser, it looks like it is from previous successfully loaded font. Meaning, the browser aggressively caches the fonts, making it look like there is a very serious error, e.g., incorrect mime type of text/html when it should be application/woff, when in reality it is just a 404 that resulted to a 404 page(seemingly), yet without the status code of 404. A page is text/html.
The docker built just don't have font files in it.
Suggestions like nginx has missing mime types for the fonts, made the error looks complex than it really is.
404s are mostly a page, so that might be reason for the content type of text/html being reported by the browser. The browser might be returning a page, but it's hard to actually know since what the browser previews is the actual font, not a page. As for why the app is not returning status code of 404, would have to find out.
Happy Coding!
nginx proxy https node express
server { listen 443 ssl; server_name domain.name.here.com; ssl_certificate /usr/local/etc/nginx/cert.crt; ssl_certificate_key /usr/local/etc/nginx/cert.key; location / { proxy_pass https://127.0.0.1:3000; proxy_set_header host $host; # proxy_connect_timeout 600; # proxy_send_timeout 600; # proxy_read_timeout 600; # send_timeout 600; } }
To create a certificate in homebrew'd nginx:
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /usr/local/etc/nginx/cert.key -out /usr/local/etc/nginx/cert.crt
Friday, January 13, 2017
Protobufjs unresolvable field type
If you got this error, one cause is there are many roots. Even if ecommerce.proto below imports the common.proto, protobufjs won't be able to resolve the message type if they are in different roots.
Instead of:
One solution:
Another solution:
Happy Coding!
Instead of:
const common = protobufjs.loadSync('common.proto'); const ecommerce = protobufjs.loadSync('ecommerce.proto'); const hr = protobufjs.loadSync('hr.proto');
One solution:
const common = protobufjs.loadSync('common.proto'); protobufjs.loadSync('ecommerce.proto', common); protobufjs.loadSync('hr.proto', common);
Another solution:
const root = protobufjs.loadSync([ 'common.proto', 'ecommerce.proto', 'hr.proto' ]);
Happy Coding!
Thursday, January 12, 2017
TypeScript + enum + node that works
If you have an internal module in TypeScript and use it on node, and wanted to add an enum on it:
task.ts:
Then the reading the value of enum would result to runtime error: 'com is not defined':
If we try to move the enum Status and make it node-compatible by putting it on separate file without the module namespace and exporting the enum, the task.ts will be interpreted as external module instead, and as such, all dotted names will be interpreted as external modules too and would result to compile-time error if they are not imported, e.g., TypeScript will complain that it has no exported member uuid on com.anicehumble even there is one defined on an internal module, as all names under com.anicehumble will now be interpreted as external modules instead.
When a module become an external one like the code below, all members (e.g., uuid) under the module com.anicehumble should be moved to task.ts and cannot be defined anymore in an internal module on a separate file; or if it will not be inlined in task.ts, uuid should be implemented as external module, and it should be imported like the importing of Enums from the-enums.ts below:
the-enums.ts:
task.ts:
To maintain the internal-ness of a TypeScript module, we will just simulate the enum, and then for the enum-using node, it will just import the external module version of the enum.
So let's define the task's status enum and make it an external module version of an enum instead. You might be wondering why we need to use const instead of enum. Later, the advantage of using const over enum will be apparent.
tasks-status-enum.ts
task.ts:
The internal module version of the enum is the export type Status = 0 | 1 | 2. We will not be directly using the numbers in node, as it will look like magic numbers, we just add that to constraint the values that can be assigned to Task's status. The code below uses magic number:
For enum-using node, this is how enum will be used:
app.ts:
And this will not work, as the status value is constrained to 0, 1, 2 values only:
This will not compile as type Status and number are not type-compatible:
and so is this, even if the value of 2 of n is in the allowable values of Status:
And now for the interesting part, we can make things more discoverable if we will make the simulated enum have a type of com.anicehumble.Status:
tasks-status-enum.ts
Adding the type to the constant, that external module version of simulated enum is now related to the internal module version of the enum (i.e., export type Status = 0 | 1 | 2)
With real enum, the type cannot be added, the following is invalid:
Update
Had I known TypeScript's const enum from the start, this post will not be written. Use const enum, it's better than what was suggested here.
Happy Coding!
task.ts:
module com.anicehumble { export enum Status { PENDING = 0, IN_PROGRESS = 1, COMPLETED = 2 } export interface Task { uuid: com.anicehumble.uuid; ownedBy: string; title: string; status: Status; } }
Then the reading the value of enum would result to runtime error: 'com is not defined':
console.log(com.anicehumble.Status.IN_PROGRESS);
If we try to move the enum Status and make it node-compatible by putting it on separate file without the module namespace and exporting the enum, the task.ts will be interpreted as external module instead, and as such, all dotted names will be interpreted as external modules too and would result to compile-time error if they are not imported, e.g., TypeScript will complain that it has no exported member uuid on com.anicehumble even there is one defined on an internal module, as all names under com.anicehumble will now be interpreted as external modules instead.
When a module become an external one like the code below, all members (e.g., uuid) under the module com.anicehumble should be moved to task.ts and cannot be defined anymore in an internal module on a separate file; or if it will not be inlined in task.ts, uuid should be implemented as external module, and it should be imported like the importing of Enums from the-enums.ts below:
the-enums.ts:
export enum Status { PENDING = 0, IN_PROGRESS = 1, COMPLETED = 2 }
task.ts:
import * as Enums from './the-enums'; module com.anicehumble { export interface Task { uuid: com.anicehumble.uuid; // TypeScript will complain com.anicehumble 'has no exported member uuid' even it is defined in an internal module on a separate file. ownedBy: string; title: string; status: Enums.Status; } }
To maintain the internal-ness of a TypeScript module, we will just simulate the enum, and then for the enum-using node, it will just import the external module version of the enum.
So let's define the task's status enum and make it an external module version of an enum instead. You might be wondering why we need to use const instead of enum. Later, the advantage of using const over enum will be apparent.
tasks-status-enum.ts
export const PENDING = 0; export const IN_PROGRESS = 1; export const COMPLETED = 2;
task.ts:
module com.anicehumble { export type Status = 0 | 1 | 2; export interface Task { uuid: com.anicehumble.uuid; ownedBy: string; title: string; status: Status; } }
The internal module version of the enum is the export type Status = 0 | 1 | 2. We will not be directly using the numbers in node, as it will look like magic numbers, we just add that to constraint the values that can be assigned to Task's status. The code below uses magic number:
const t : com.anicehumble.Task = <any>{}; t.status = 2; // http://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad
For enum-using node, this is how enum will be used:
app.ts:
import * as TaskStatus from './task-status-enum'; const t : com.anicehumble.Task = <any>{}; t.status = TaskStatus.IN_PROGRESS; console.log(TaskStatus.IN_PROGRESS); // no more undefined error
And this will not work, as the status value is constrained to 0, 1, 2 values only:
t.status = 42; // compile error: 42 is not assignable to type Status
This will not compile as type Status and number are not type-compatible:
const n: number = 42; t.status = n; // compile error: number is not assignable to type Status
and so is this, even if the value of 2 of n is in the allowable values of Status:
const n: number = 2; t.status = n; // compile error: number is not assignable to type Status
And now for the interesting part, we can make things more discoverable if we will make the simulated enum have a type of com.anicehumble.Status:
tasks-status-enum.ts
export const PENDING : com.anicehumble.Status = 0; export const IN_PROGRESS: com.anicehumble.Status = 1; export const COMPLETED: com.anicehumble.Status = 2;
Adding the type to the constant, that external module version of simulated enum is now related to the internal module version of the enum (i.e., export type Status = 0 | 1 | 2)
With real enum, the type cannot be added, the following is invalid:
export enum Status { PENDING : com.anicehumble.Status = 0, IN_PROGRESS: com.anicehumble.Status = 1, COMPLETED: com.anicehumble.Status = 2 }
Update
Had I known TypeScript's const enum from the start, this post will not be written. Use const enum, it's better than what was suggested here.
Happy Coding!
Sunday, January 1, 2017
Error: request entity too large
return this.$http.post( '/great/api/-core/file/jpg', formData, { transformRequest: angular.identity // , headers: { 'Content-Type': undefined } // uncomment this to remove the error: Request Entity Too Large });
Happy Coding!
Subscribe to:
Posts (Atom)