Create-React-App uses babel to transpile the TypeScript so it isn't using your npm installed version of TypeScript. Version 3.3.0 of react-scripts supports TypeScript 3.7. You can install it and use it with:
yarn add [email protected]-or-
npm install -s [email protected]
Create-React-App uses babel to transpile the TypeScript so it isn't using your npm installed version of TypeScript. Version 3.3.0 of react-scripts supports TypeScript 3.7. You can install it and use it with:
yarn add [email protected]-or-
npm install -s [email protected]
package.json
{
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom"
},
"devDependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
"customize-cra": "^0.4.1",
"react-app-rewired": "^2.1.3"
}
...other
}
config-overrides.js
const { useBabelRc, override } = require('customize-cra');
module.exports = override(useBabelRc());
.babelrc
{
"plugins": ["@babel/plugin-proposal-optional-chaining"]
}
detailed blogpost
Hi,
I'm getting the following error using one of the newer features of Typescript 3.7 with Create React App:
Support for the experimental syntax 'optionalChaining' isn't currently enabled
Add @babel/plugin-proposal-optional-chaining (https://git.io/vb4Sk) to the 'plugins' section of your Babel config to enable transformation.
The error only appears on run time; type checking resolves fine on the Intellij Typescript plugin.
And I did add the above plugin to .babelrc.
I'm using:
Create React App @3.2.0,
React@16.10.0,
Typescript@3.7.0-beta,
Optional Chaining Proposal Plugin @7.6.0
What am I missing here?
An idea to get rid of optional chaining with you current setup would be to statically type the state of the world and write different components.
Not sure I structured your store correctly but you get the idea.
type RootState = {
app: 'init' | 'running' // we model the state of the app
post: {
Targetfarms: Farmstype | null
}
}
// We dispatch to the correct implementation depending on the state of the world
const MainPage = () =>
useSelector({ app }: RootState) => app) === 'running'
? RunningPage()
: InitPage();
const RunningPage = () => {
const { Targetfarms } = useSelector((state: RunningState) => state.post);
// OK
const f = Targetfarms.placeId
}
const InitPage = () => {
const { Targetfarms } = useSelector((state: InitState) => state.post);
// @ts-expect-error: Targetfarms is possibly null
const f = Targetfarms.placeId
}
There are many ways to produce the different states. This is an option.
// When the app is 'running' `post/Targetfarms` is unlocked
type RunningState = Unlock<RootState, ['post', 'Targetfarms']> & {
state: 'running'
};
// Otherwise Targetfarms is still nullable
type InitState = RootState & {
state: 'init'
};
type Unlock<State, Path extends PropertyKey[]> = unknown & {
[K in keyof State]: K extends Path[0]
? Path['length'] extends 1
? NonNullable<State[K]>
: Unlock<
State[K],
Path extends [PropertyKey, ...infer U] ? U & PropertyKey[] : never
>
: State[K]
}
This solution can start to become interesting if you have few app states and lots of nullable pieces of state. Basically you take the decision of what state the app is in once at the root instead of many times where the values are needed.
Maybe that you are trying to access a property of an object that may be null or undefined before the initialization. To avoid this error, you have a few options:
You can check if the object is null or undefined before trying to access its properties. For example:
if (Targetfarms) {
console.log(Targetfarms.placeId);
}
You can set a default value for Targetfarms using the || operator. For example:
const {Targetfarms} = useSelector((state: RootState) => state.post) || {};
console.log(Targetfarms.placeId);
This will set the default value of Targetfarms to an empty object, which means you can access its properties without getting an error.
Note: I think and it's only my opinion here, optional chaining it's a good approach to avoid null or undefined.
I'm trying to enforce the use of optional chaining for accessing properties of any type object in TypeScript to avoid potential runtime errors. For example, I want the following code to throw a TypeScript error:
catch(e: any) {
const code = e.code; // This should throw a TypeScript error
}But this code should not throw an error:
catch(e: any) {
const code = e?.code; // This should not throw a TypeScript error
}Is there a way to configure TypeScript to enforce this rule or any workaround to achieve this behavior?
The problem is you are targeting esnext this will tell the compiler to output all language features as is without any transpilation. Set the language to es2020 (or below) and ?. and ?? will get transpiled to compatible code:
Copy(async function () {
let imageFileId = (await db.query(sql`select id from image_files where sha256=${sha256}`))[0]?.id;
})()
Playground Link
There is no fine-grained control over which language features get transpiled and which don't do you have to pick a version as a whole unfortunately,
Well, I didn't want to use Babel because then I'd have to figure out how to replace ts-node. There's a bunch of outdated docs out there referring to old Babel packages, but these instructions should work as of Nov 2019:
Add a .babelrc file:
Copy{
"presets": [
["@babel/preset-env",{"targets": {"node": "current"}}],
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-syntax-bigint"
]
}
Add these deps:
Copy "devDependencies": {
"@babel/cli": "^7.7.0",
"@babel/core": "^7.7.0",
"@babel/node": "^7.7.0",
"@babel/plugin-syntax-bigint": "^7.4.4",
"@babel/preset-env": "^7.7.1",
"@babel/preset-typescript": "^7.7.0",
"@types/node": "^12.7.5",
"typescript": "^3.7.2"
}
Execute your code with:
Copynode_modules/.bin/babel-node --extensions ".ts" src/index.ts
The --extensions ".ts" is very important, even though you're explicitly trying to execute a .ts file, it won't transpile it w/out that.
I like to use GNU Make instead of package.json scripts:
CopyMAKEFLAGS += --no-builtin-rules
.SUFFIXES:
NM := node_modules/.bin
.PHONY: build start dev clean test publish
## commands
########################################
__default:
$(error Please specify a target)
build: build-types build-js dist/package.json
build-types: node_modules/.yarn-integrity
$(NM)/tsc --emitDeclarationOnly
build-js: node_modules/.yarn-integrity
$(NM)/babel src --out-dir dist --extensions ".ts" --source-maps inline
run: node_modules/.yarn-integrity
$(NM)/babel-node --extensions ".ts" src/index.ts
check: node_modules/.yarn-integrity
$(NM)/tsc --noEmit
dist:
mkdir -p $@
clean:
rm -rf node_modules dist yarn-error.log
dist/package.json: package.json | dist
jq 'del(.private, .devDependencies, .scripts, .eslintConfig, .babel)' $< > $@
## files
########################################
node_modules/.yarn-integrity: yarn.lock
@yarn install --frozen-lockfile --production=false --check-files
@touch -mr $@ $<
yarn.lock: package.json
@yarn check --integrity
@touch -mr $@ $<
Or just copy from Microsoft's TypeScript Babel Starter.
At time of writing, TypeScript does not support the optional chaining operator. See discussion on the TypeScript issue tracker: https://github.com/Microsoft/TypeScript/issues/16
As a warning, the semantics of this operator are still very much in flux, which is why TypeScript hasn't added it yet. Code written today against the Babel plugin may change behavior in the future without warning, leading to difficult bugs. I generally recommend people to not start using syntax whose behavior hasn't been well-defined yet.
Update Oct 15, 2019
Support now exists in [email protected]
Say thanks to https://stackoverflow.com/a/58221278/6502003 for the update!
Although TypeScript and the community are in favor of this operator, until TC39 solidifies the current proposal (which at the time of this writing is at stage 1) we will have to use alternatives.
There is one alternative which gets close to optional chaining without sacrificing dev tooling: https://github.com/rimeto/ts-optchain
This article chronicles what the creators were able to achieve in trying to mirror the native chaining operator:
- Use a syntax that closely mirrors chained property access
- Offer a concise expression of a default value when traversal fails
- Enable IDE code-completion tools and compile-time path validation
In practice it looks like this:
import { oc } from 'ts-optchain';
// Each of the following pairs are equivalent in result.
oc(x).a();
x && x.a;
oc(x).b.d('Default');
x && x.b && x.b.d || 'Default';
oc(x).c[100].u.v(1234);
x && x.c && x.c[100] && x.c[100].u && x.c[100].u.v || 1234;
Keep in mind that alternatives like this one will likely be unnecessary once the proposal is adopted by TypeScript.
Also, a big thanks to Ryan Cavanaugh for all the work you are doing in advocating this operator to TC39!
For some reason I can't use optional chaining in my new project, other TS features like interfaces, types, ... are working fine. Also my IDE is not throwing out any errors, but upon compiling the code, I get this error for the following line of code:
Line of code: country: location?.country
country: location?.country,
SyntaxError: Unexpected token '.'
at Module._compile (internal/modules/cjs/loader.js:895:18)
What's going on?