You can accomplish this with the new template literal type support in TS. Be warned, though... it'll probably be more annoying than useful.
Here's an example with valid IDs containing a, b, or c and of length 5. Change Char
and ID
to adjust those parameters.
type Char = "a" | "b" | "c"
type ID = ${Char}${Char}${Char}${Char}${Char}
// fails const id1: ID = "abcde" // d and e aren't valid const id2: ID = "ab" // wrong # of letters
// passes const id3: ID = "abaaa" const id4: ID = "ababc"
I find the official Typescript docs to be a very good resource, they nailed it with their documentation
Here's the section from the docs.
Their suggestion is:
> If you would like a heuristic, use interface
until you need to use features from type
.
> One thing I’m struggling with, though: I have a class with a few attributes that get their values in different phases.
Use a builder pattern: playground
You have strictNullChecks disabled (this is TS default). I recommend setting the project to strict mode by adding strict: true
to your tsconfig
This feels like pedantry, but... This isn't an example of TypeScript 'making types real' or TypeScript doing run-time type-checking. The type guards are just Javascript, and all the runtime type-checking that is being done here is being done by Javascript. However, TypeScript understands (or can be made to understand) these type guards, and can thus use them for type inference in the following code.
Which is nice, but you don't need to use TypeScript to do the runtime type checking that is being done in this article.
>Do you need to change your target library? Try changing the lib compiler option to 'es2015' or later.
The error is telling you you need to update your lib property in tsconfig. Older versions of JS don't have the fill method, and TS doesn't know what env you're trying to support so it won't let you do it
More information in the official docs: https://www.typescriptlang.org/tsconfig#lib
Specifically, it's a "definite assignment assertion". More info: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html
It's only necessary if you use --strictPropertyInitialization. Otherwise it's a no-op.
You've probably already dome it, but start here and read through the TS handbook: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
Given you're experienced in JS I'd just say aim to recreate a small to mid sized project you've previously done to gain an appreciation of the benefits of TS over JS.
TS isn't dramatically different, but it is notably different to JS!
I had to look up what the “is” operator does since I had not used it before. It was slightly annoying to google because “is” is a common word, so here’s the documentation for anyone else.
https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
It's not "!:", it's just "!", the other stuff is part of whatever else you're doing there. This is the "non-null assertion operator": https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator
You're telling Typescript "I promise this value will never be null, so don't nag me about not checking it before referencing".
Yup, TypeScript is its own thing which isn't tied to any framework/library. You can use it with regular JS, other frameworks like React, etc. You can even use it on the server-side with Node.
If you haven't already, install node/npm here: https://nodejs.org/en/
Then, install TypeScript globally by running this in your terminal:
$ npm install -g typescript
Then, just navigate to your project folder and run:
$ tsc --init
This will automatically create a tsconfig.json
file for you which will allow you to start using TypeScript.
If you want to customize how TypeScript works with your project, you can change settings in the tsconfig.json
file. You can see specifics on what you can do here: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
If you’re willing to spend $30, I wrote O’Reilly’s Programming TypeScript, which goes into depth on all of TypeScript’s features (including more advanced ones that I haven’t seen covered elsewhere). I also tried to explain the “why” behind each of those features, and what kinds of problems they help you solve. The book was edited by Daniel of the TypeScript team, and has tons of examples, exercises, pictures, explanations, etc.
https://www.amazon.com/gp/product/1492037656
If you don’t have $30 to spend, the book is on Safari, which has a free trial: https://learning.oreilly.com/register/.
Or if you don’t have the time to read a whole book, check out one of the online resources people in this thread linked — the TS handbook and Marius’s blog are both great.
This was my first time hearing about this event. Really cool!
Here's what I came up with:
type EventsType = {
[BookType in Books as on${BookType['genre']}
]?: (e: BookType) => void
}
Link to playground
The biggest problem with TS is that the type system is kind of quirky. It's mostly due to the fact that it assumes that no side effects ever happen. Which is fair, but it can lead to some uncomfortable situations (warning: contrived example), or situations where you've worked around some limitation in the type system via `any`, `as`, or `!`, and then are bitten in the ass later because some "invariant" you were upholding turns out to not be so invariant...Still better than debugging type errors at runtime.
Completely depends on the project, and how strict they felt like being.
Unless all the contributors spent the up-front effort to avoid any
and eliminate warnings and errors (and fail the build as soon as any are reintroduced), I don't get the fearless refactoring I do with Elm.
Hey mate this is an ESLint rule - you can configure ESLint rules to your liking with a .eslintrc.js
file.
The specific rule you're talking about is this one https://eslint.org/docs/rules/no-unused-vars
In your ESLint config file, you can specify if this rule should be an error or a warning or off.
"off" or 0 - turn the rule off
"warn" or 1 - turn the rule on as a warning (doesn't affect exit code)
"error" or 2 - turn the rule on as an error (exit code will be 1)
​
I don't know exactly what you'll need to put in the eslintrc file but it'll be something like:
"rules": {
"no-unused-vars": "warn"
},
​
Up to you but I'd recommend just spending 5-10 minutes understanding how to configure
ESLint to your liking as well, if you're planning on continuing to use the plugin.
The old module
has been renamed namespace
.
A note about terminology: It’s important to note that in TypeScript 1.5, the nomenclature has changed. “Internal modules” are now “namespaces”. “External modules” are now simply “modules”, as to align with ECMAScript 2015’s terminology, (namely that module X { is equivalent to the now-preferred namespace X {).
https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html
This system is still supported, but designed for client-side code without module system or bundler.
Most bigger JS apps now is either Node.js or uses a bundler -- webpack, babel, browserify, requirejs, maybe also ES6 async loader in the near future. The new module system can compile down to support those:
I would follow ES6 module system if your bundler is compatible enough. ``` import * as jquery from 'jquery'; import MyClass from './MyClass'; import namedExport1, namedExport2 from './MyUtil';
export default MyClass; export { namedExport1, namedExport2 }; ```
Hm. I think there is maybe a misunderstanding here. Java has quite stricter runtime typechecking than that. Java has "type casts" which are checked at runtime, TypeScript has "type asserts" which are not checked at runtime and the user has to do the checking. See this Java example vs this TS example.
It may seem trivial but in the Java example the error shows up when you attempt to assign an A
to a B
where as in the TS example the error shows up when you attempt to invoke foobar
.
In practice I find this has a large impact, earlier errors are always better IMO.
typescript occasionally generates runtime code for you (eg if your target doesn't support async) but yeah it's pretty rare. In general the fact that typescript doesn't exist at runtime is probably why people get confused if they're used to other languages
You can extend multiple interfaces and have those properties on the new one.
Example from handbook:
interface Shape { color: string; }
interface PenStroke { penWidth: number; }
interface Square extends Shape, PenStroke { sideLength: number; }
let square = <Square>{}; square.color = "blue"; square.sideLength = 10; square.penWidth = 5.0;
I liked this explanation but I wanted something I could play with, so I've made some examples in this playground.
type TypedAtCallsite = <T>(t: T) => T
type TypedAtDefinition<T> = (t: T) => T
type Counter = {count: number}
const logAndReturn: TypedAtCallsite = (thingToLog) => {
console.log(thingToLog)
return thingToLog
}
const addToCounter: TypedAtDefinition<Counter> = (counter) => ({
count: counter.count + 1
})
logAndReturn<Counter>({count: 5})
addToCounter({count: 5})
Using discriminated unions seems to work
Echoing what other people have mentioned, TS is compiled down to JS at the end of the day. Although it's not essential starting out, eventually you'll need to know it if you want to do it professionally.
You can compare what the resulting JS is using https://www.typescriptlang.org/play/
If you are using a 'tsconfig.json' the option you want is 'outDir', you can read more about it here. Also you might wanna give Microsoft's VSCode a shot. It supports any OS, and it is really good for typescript and Node debugging. I used Sublime for as long as I can remember, and I've now switched completely to VSCode.
You're trying to using interface declaration merging to change the definition of Task
. But declaration merging cannot change the type of an interface property - it can only add properties. From the handbook:
> Non-function members of the interfaces should be unique. If they are not unique, they must be of the same type.
In this case you're trying to change the property type from string
to a subtype of string
, and yes "choice"
is assignable to string
- but it's still a different type.
You just need to use generics on the class in the same way you'd use generics on a function.
Hope this is not a stupid question.
I have an array with some elements that could be null
.
I filter out those values but TS doesn't know and still thinks that a value could be null
.
What's the best approach here? I could simply slap a promotions?.discount
in there and the error would go away, but maybe there's a cleaner way to tell TS "at this point the array has been filtered so it's guaranteed that there are no more null
values".
Thanks in advance.
The only way you can do this is to wrap both parameters into a single object:
interface UnknownEntity { type: string; }
interface UnknownEntityPair { x: UnknownEntity; y: UnknownEntity; }
interface EntityA { type: "a"; }
interface EntityAPair { x: EntityA; y: EntityA; }
const bothAreEntityA = (pair: UnknownEntityPair): pair is EntityAPair => { const {x, y} = pair; return x.type === "a" && y.type === "a"; }
Here's an example.
Thats the non-null assertion operator. Basically tells Typescript to remove possible null or undefined values from a type. Generally useful when trying to access a nested property or method on something that may be null in some cases, but you know won't be in a given context.
To echo this and provide a little more to the OP:
Because your parameter type was (c: string) => void
you are correct that it is a required parameter (non-optional). But that requirement only exists when calling the function, not defining a function to conform to the type.
I've taken your original typescript playground and extended it to show the difference:
Yup. Can confirm yourself on TS playground here.
You can use the <code>@typedef</code> and <code>@property</code> JSDoc tags to create a pseudo-interface declaration inside a regular .js
file. You can't create an actual interface, though. Check out the link for more JSDoc tricks for TypeScript.
Alternatively, put your interfaces in a separate d.ts
file.
So the reason this happens is because TS only knows that the items in there are Drawable
s, and not that they are Hero
es. You basically have two ways of fixing this:
a) Remove the explicit type declaration for characters
(or define all keys explicitely) so TS infers the type automatically as { heroArray: Hero[], zombieArray: Zombie[]
. Then TS knows that this object has only the keys heroArray
and zombieArray
and the types of those, respectively.
b) If you want to keep it as a collection of Drawable
s, the quick and dirty way is suggested by /u/blood__drunk below; Just cast it and tell TS "I know better than you". The more beautiful way is writing a so called "User Defined Type guard" Docs:
const possibleHero = characters.heroArray[0]; if (isHero(possibleHero)) { possibleHero.whatever(); }
function isHero(drawable: Drawable): drawable is Hero { return typeof (<Hero>drawable).whatever === 'function'; }
This allows you to programmatically decide if the variable is a hero, a zombie or whatever and then call these specific methods on it.
This is a very primitive example, but it describe the issue:
interface Data { data: string; value: string; }
function getData(): Data { const result = { data: 'data', value: complexSlowMethod() }; return result; }
Assume that complexSlowMethod()
is a method that aggregates the data for value
. The type of result
is inferred to be { data: string; value: string }
, it is not inferred to be Data
. Now when returning result
the TypeScript compiler will check if the type of result
is compatible with the return type, which is the case. Sounds okay, so far. But if you later decide to remove the value
property from Data
, then the code will continue to run just as is. If you're explicit with the type of the variable result
by writing const result: Data = {..}
, then instead the TypeScript compiler will complain: Object literal may only specify known properties
, so the TypeScript compiler supports you and tells you about an unknown property, about (potentially slow) code that can be removed because it's not needed anymore. If you infer the type, compatibility is just checked, and it's compatible. By being explicit TypeScript will support you in eliminating unwanted properties.
The code works fine, but if you annotate the type explicitly TypeScript will warn you about the value
property that is not part of the interface.
I’ve been using Prisma https://www.prisma.io and I’m happy with it. The downside is that it doesn’t support as many databases as Sequelize.
I use it with blitzjs https://blitzjs.com it’s a full framework that uses Prisma as their ORM
This is my solution! The UnionIntersection type pretty much is what I needed, thanks a bunch!
Hi, here you can see an example where the "outDir" option is used to do precisely that. https://www.typescriptlang.org/tsconfig#outDir
I think you should absolutely use it to have your transpiled files in a separate directory. This will make your life easier when scrolling through your files, using git (with .gitignore), deleting+rebuilding all transpiled code, etc.
If they are differnet, then that isn't really an interface that you can extend. You could create a single type that uses template literal types to interpolate a string into the key from a generic.
While cool that the compiler supports this, I find it way too annoying to use in practice (unless there is a need for super safe, like formally verified levels safe, code, but then maybe TS might not be the best choice anyways). To ensure a normal array is non-empty and make it be accepted by the type, one can't just use basic condition checking, custom type guards must be used instead all over the place (or I guess you could just cast it, but that to me kind of defeats the effort in the first place).
Similarly when you have a non-empty array that is actually accepted by the type (whether it was directly instantiated as such, type guard checked, and or manually cast), you can fool the type checking even with basic operations like .pop(), which don't change the type and now you have a false sense of security.
I think a better solution if one really wants a bit more security at the cost of more bloated and annoying-to-write code, is using the checked indexed accesses compiler option. And extensive high coverage tests of course.
I just tested a toy example in the TS Playground, and it looks like it works to me.
const x1: /applications/${string}/commands
= '/applications/test/commands';
const f = (param: /${string}
) => param;
const x2: /${string}
= f(x1);
Here's a playground with this approach. The only issue I found was that it only enforces that all keys and values are present, not necessarily that the key and value are always the same. They can be swapped and the type will still be valid.
Something like this?
interface IApplication { id: number; createdAt: string; applicationStatus: "INTERVIEWING" | "RESUMESUBMITTED" | "OFFERRECIEVED"; url: string; }
declare function count(applications: IApplication[]): Record<IApplication['applicationStatus'], number>
// ...which is eqivalent to declare function count2(applications: IApplication[]): { [K in IApplication['applicationStatus']]: number }
const numInterviewing = count([]).INTERVIEWING // inferred as number
And given that op is new to typescript :
(A | B | C) extends undefined ? true : false
by definition is :
(A extends undefined ? true : false) | (B extends undefined ? true : false) | (C extends undefined ? true : false) |
And if one of A
,B
,C
is undefined the one of the previous for lines is true which leads to the result :
true | false | false
which actually is :
true | false
i.e
boolean
But here is how I would do it. You should treat extends in types like some kind of equality.
This is a good question, I was also confused for a bit after reading it.
The thing is, the way you defined hashMap
, you told typescript that every key of hashMap always is a { valueNumber: number; valueString: string; }
. This might not be intuitive, but when you are doing hashMap[stringKey] || "string";
, TS believes that hashMap[stringKey]
is always defined, and therefore the value after the ||
is not even considered in the type resolution.
If you want these ||
to act as you expect, you have to tell TS that hashMap[something]
might not be defined, like so:
const hashMap: { [key: string]: { valueNumber: number; valueString: string; } | undefined; } = {};
> Java or Rust
I'd rather bang my balls with a hammer than use any of those.
The first is a cancer of a language, with the OO paradigm nobody even implements decently. Happy it's getting phased out on the front end by Kotlin, can't imagine Java dying on the server side for decades tho, if ever.
As for Rust, I like it, but it is too much of a complex language to even imagine monkey programmers (99% of us) using it on a daily basis. Most people I see struggle with simple generics in TypeScript that to think they could use Rust is madness.
I also don't share your look on JS, it's a very nice language, I wish it had a static type system because TS will always have its limitations due to having to be 100% ecmascript compliant and some things are just impossible to type correctly (like a curry function, you just can't, even if you go his lengths, it still doesn't work: https://www.freecodecamp.org/news/typescript-curry-ramda-types-f747e99744ab/ ).
Answering OP's question: I really miss pattern matching https://github.com/tc39/proposal-pattern-matching
I loved it when I was working full time in that environment, and it's almost certain that the new TypeScript website will be built that way.
Best starter recommendations are:
You absolutely can create functions that will determine if a value conforms to a certain type/interface. They're called type guards. Here is some documentation.
So type guards are cool, however you have to rely on correctly implementing the function, as well as updating it should your type/interface change. This is time consuming and error prone.
There are libraries to help with this. One I recently stumbled upon which I like is runtypes. It's great because you can define your type/interface and the guard at the same time. You can then use it as a type/interface, and it also provides helper methods to check that a given unknown value conforms.
import \* as rt from 'runtypes';
export const Request = rt.Record({
username: rt.String,
password: rt.String,
});
export type Request = rt.Static<typeof Request>;
const myValue = {};
if (!Request.guard(myValue)) {
// myValue does not conform to Request
}
I believe the favored model is to export each function and allow the use of external modules instead of exporting an internal one. That's assuming you're working with modules and not the global scope.
See the "Do not use namespaces in modules" section at the bottom of the page.
https://www.typescriptlang.org/docs/handbook/modules.html
A snippet: > When first moving to a module-based organization, a common tendency is to wrap exports in an additional layer of namespaces. Modules have their own scope, and only exported declarations are visible from outside the module. With this in mind, namespace provide very little, if any, value when working with modules.
Keep in mind that naming collisions are handled by the importer using the 'as' keyword.
If you first filter out the keys that you don't want, then your resulting type won't have those nasty : never
properties either. And the infer U
is pointless if you don't use U
, so you can just use any
.
type OutputCallbackKeys<T> = { [K in keyof T]: T[K] extends EventEmitter<any> ? K : never }[keyof T]; type OutputCallbacks<T> = { [K in OutputCallbackKeys<T>]: T[K] extends EventEmitter<any> ? () => void : never; };
OutputCallbackKeys
will be a union type of string literal types that map to all properties that extend EventEmitter<any>
.
Ping /u/tme321
I think you’re wrong about that first part.
{ [clientId: string]: MyType }
defines a dictionary/hash object with dynamic string keys of MyType
values. Not the return type of a function call.
I agree with the second part, but here’s a bit more detail:
IConnection & { client}
is an intersection type that should throw a compilation error in most cases because the type of client
is not explicitly declared, it will be considered any
if it compiles at all.
MikroORM seems like the spiritual successor to TypeORM, people seem to love it. https://mikro-orm.io/
For a different direction, there’s Prisma. A lot of people love it and they do a ton of developer outreach. I bet someone from the company that makes it will show up to comment now that their name has been mentioned. They released a schema migration tool sometime in the last six months that looks amazing and would probably convince me to give it a go if I was starting a new project. https://www.prisma.io/
I’m confused because this is what typescript does.
If you use .ts files you get red squiggles and errors in your editor. You might want to make sure you’re using the typescript plugin for your editor. Here’s an example using VS Code: https://code.visualstudio.com/docs/languages/typescript
But typescript is static typing for JavaScript. So everything your used to, developer experience wise, you’ll get with typescript!
Looks like maybe you have a different tsconfig in your environment vs in the playground. For example if I enable useDefineForClassFields
, then I get different behavior. I think the expected behavior here is not strictly defined and I wouldn't rely on it acting a certain way.
The function 'getIndex()' takes a Line or Rectangle type. This means that 'geometry' is either a Line or a Rectangle. The classes Rectangle and Line method getIndex only accept one type.
Use an interface to solve it: (untested)
interface Geometry { getIndex(node: number, geometry: Geometry): number; } function getIndex(geometry: Geometry) { geometry.getIndex(1, geometry); // Argument of type 'Line | Rectangle' is not assignable to parameter of type 'Line & Rectangle'. // Type 'Line' is not assignable to type 'Line & Rectangle'. // Property 'width' is missing in type 'Line' but required in type 'Rectangle'.ts(2345) }
class Line implements Geometry { x1: number; constructor() { this.x1 = 10; } getIndex(node:number, geometry: Geometry) { //some math here ... return 0; } }
class Rectangle implements Geometry { width: number; constructor() { this.width = 10; } getIndex(node:number, geometry: Geometry) { //some math here ... return 0; } }
Playground:
Hey everyone! Author here
I'm super proud of the type system we were able to build around react navigation and think it can help a lot of people out if you're working in a large react-navigation codebase. It also makes use of some very cool recent language features such as Template Literal Types and Variadic Tuple Types.
Have you tried the triple slash directive: https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
For the extensions I have made in Azure DevOps I have to include at the top of my files:
/// <reference types="vss-web-extension-sdk">
That way I can access the globally scoped variables that the DevOps library exposes on its own, but still get the type hinting/safety of the library.
Try doing that with a reference to your gtag library.
I hope this does what you want. It became quite easy to do with the recent addition of template literal types.
As the earlier poster /u/iams3b said, there's nothing wrong with the code, but if you target an earlier ES version, you do get an error on TS Playground.
Perhaps follow the advice in the error message and target ES2015 or later..
Look at the Utility Types for inspiration https://www.typescriptlang.org/docs/handbook/utility-types.html
In your example, B could be defined in terms of A as
type BAttrs = Pick<A, 'a'>; interface B extends Omit<A, keyof BAttrs> { attributes: BAttrs }
You can manually set the type of this
in a function by specifying a this
parameter:
required: function(this: YourType) { ... }
The TypeScript Handbook has a section on "Declaring this in a Function" if you want to know more.
You can narrow down the type with an intersection.
interface Props<T, S> { fn?: (response: S) => T[]; enable?: boolean; }
export interface Updater { updater: () => void; }
export type Result = { irrelevant?: any; };
export type CombinedResult = Result & Updater;
export function foo<T, S>(props: Props<T,S> & {enable: true}): Updater export function foo<T, S>(props: Props<T,S> & {enable: false}): Result export function foo<T, S>(props: Props<T, S>): CombinedResult | Result { if (props.enable === true) { return { updater: () => { console.log("updater!"); } }; }
return {}; }
const { updater } = foo({enable: true})
Yeah, if only Node had some sort of modules that one could import from some sort of package repository to facilitate code reuse... but I guess we’re stuck always rewriting everything from scratch.
This is a distributive conditional type.
>Distributive conditional types are automatically distributed over union types during instantiation
What this means is that when you do Extract<AB, BC>
, what's actually happening under the covers is that each individual member of that string union AB gets checked, and then everything gets joined back together at the end
type AB = 'a' | 'b' type BC = 'b' | 'c'
// Extract on this really looks like: 'a' extends 'b' | 'c' ? 'a' : never; // This is never 'b' extends 'b' | 'c' ? 'b' : never; // This is 'b'
This means that Extract<AB, BC>
is 'b' | never
, which is simplified down to just 'b'
There're 2 ways that I know of:
tsconfig.json
has an option called outFile
: image.
You must set option module
to "AMD"
or "System"
to use this.
Read more from TypeScript handbook.
You should set option module
to "commonjs"
(i.e. convert import
to require
) in tsconfig.json
.
In your tsconfig set “lib”: [“es2018”] or you could do es2017, esnext, or es7. All of that stuff is already supported by the ts compiler.
https://www.typescriptlang.org/docs/handbook/compiler-options.html
I avoid nested ternaries at all costs, so it would be option 1 for me, but then I also avoid reduce() wherever possible, so I might not be the best person to answer this.
I factor the intuitive nature and maintainability into my definition of "good" code over shortness, so while a one-line solution might be cool, I'll almost always spell it out so "future me" can fix it easier when it needs fixing.
Edit: I didn't actually say anything helpful here! Here's a codesandbox with a couple of alternatives: https://codesandbox.io/s/dank-voice-otr7e?file=/src/reduce.js
Option 3 - Use JS's falsey logic to turn undefined
s into 0
Option 4 - If you have lodash already, let a well-tested library do the work for you
I can't give you a definitive answer on why it is so, but I can show you a reproducible example:
EDIT: I found a way to "fix" it. if you extend the B interface like this:
interface B extends Record<string, object | undefined>{
world: undefined
}
then it will work
"module": "commonjs"
in tsconfig.json ought to do it (more info here), though this is usually something you configure your bundler to do. Far as I know, webpack still outputs commonjs by default.
I like the idea of xhtml too, but alas it'll likely remain something of a white elephant forever.
Turns out I'm using a slightly outdated version of TS. I'm currently on 4.2.4
Problem here is that when you use destructuring, TypeScript looses information needed to narrow down type. Modify your code, so your check is attached to props.
You can achieve that with function overloads (TS handbook section about overloads) as demonstrated in this playground
Do you have strict null checking off? You may want to ensure that's on. Here's the same example with it turned off and there is no error showing (but it will problems).
VSCode natively understands TS, so if you start using TS I don't think you need to do anything for the editor to start giving you hints et al.
You probably get the jsdocs hints because VSCode interprets it as TS https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
I don't know of any TS tutorials/beginner guides that also introduce JS concepts. IMHO, you'll be better prepared going through the JS section of https://freecodecamp.org/ then the TS handbook https://www.typescriptlang.org/docs/handbook looking into advanced concepts as you encounter them (they're pretty rare in application code, but common in library code)
You can't do such things with middleware. You could hardcode your types to not have undefined if you're always using a middleware which would mean that the properties will always exist, or you could use a function with typeguard instead of middleware.
Had to switch back briefly for a project, and at the time, My cofounders were not ready to hire TypeScript developers (difficulty finding candidates and salary considerations in the future). So I was forced to work with plain JavaScript and Meteor.
It’s all over now though. I retired from the project. Now they’re back to PHP and I’m building my own CMS in TypeScript. Everyone is happy.
Check out conditional distribution. A way to prevent this from happening is if you make the condition something other than just a bare variable (as in A extends B
). A common trick is to use [A] extends [B]
instead.
Dynamic and 'any' are similar but I'd recommend avoiding using 'any' unless you have a really good reason. Just like in C# there is a limited preferred number of use cases for dynamic. Here are some reasons to use 'any' in typescript:
Reasons not to use 'any':
Think hard about it whether 'any' is a good idea. Usually you can leverage typescript to your advantage where 'any' is unnecessary.
Would an enum work?
enum Pets{
Cat = 'cat',
Dog = 'dog',
Horse = 'horse'
}
const someValue: string = 'cat'
if (Object.values(Pets).includes(someValue)) {
// Do stuff here
}
This works because Pets converts into:
{Cat: "cat", Dog: "dog", Horse: "horse"}
Enums can also be used as types:
const someValue:Pets;
You've got a couple simple options off the top of my head:
Put your definitions in index.d.ts in the project root, ala the DefinitelyTyped packages (or just re-export them there)
Populate the types
field of your package.json, as shown in the docs
> For example using _.filter(array, item => ...) can't infer item from array because they're siblings.
Uhhh... This is not true.
function filter<T>(array: T[], fn: (item: T) => boolean): T[] { return array.filter(fn); }
const arr: number[] = [1, 2, 3];
filter(arr, /* item is inferred to be number here */)
If you haven't found it already, I've had a great experience on Mac OS X with Atom and the TypeStrong plugin (note: there are several plugins for TS, but the TypeStrong one seems the... er... strongest).
It's actually slightly ahead of Visual Studio in some respects. e.g. it already supports the tsconfig.json
project file format that is slated for TS 1.5, with some extensions that mean you barely have to do anything with it manually.
It's also faster at updating the UI when you fix a type or syntax error.
Can't recommend it highly enough.
JSX is part of React. It has been developed for React to work with in the first place and so far I don’t know of any other framework/library to implement it (Vue might, but I’m not sure since it uses different syntax). This JSX gets translated to JS code which is then run in virtual DOM to then render into real DOM for the ease of use and performance since it’s much easier to compare two virtual DOMs. I’d suggest you to read through docs first before you start developing hacky ways to finish your task.
Node added support for this in v14. That was released last April, but I'm surprised your tooling is defaulting to it already. What version of vscode are you using? Any relevant extensions?
Yeah I read that React throws Promises to simulate algebraic effects, and I agree with why it defaults to unknown
.
I guess I was hoping for a way to enforce this within my own codebase in TypeScript itself, not a linter (I'm aware of no-throw-literal), to also get the benefit of not needing to check every single catch
clause. Seems like there's no way around it unfortunately, and I'm stuck working in a codebase with exceptions thrown around everywhere.
https://developer.mozilla.org/en/docs/Web/API/SharedWorker
That would be probably the cleanest way to handle it. SharedWorkers aren't supported by Edge and Safari yet, however.
Imo Either makes the most sense as part of an fp framework, since it fits nicely within the ecosystem. Without the tools and structure of the framework it kind of falls flat. Check out https://dev.to/gcanti/getting-started-with-fp-ts-either-vs-validation-5eja
This covers what I could make out of the problem statement
Well, what do you ultimately want to achieve? It is not quite clear to me. Do you want to be able to extract all static methods from one type and do something with it like this ? Here an object having all static methods from BaseClass must be supplied to IsAClass(..)
This is because Fn2
is assignable to Fn1
, but not to Fn3
.
type Fn1 = (x: string) => void; type Fn2 = () => number; type Fn3 = (y: number) => string;
declare const f1: Fn1; declare const f2: Fn2; declare const f3: Fn3;
const test1: Fn1 = f2; // OK const test2: Fn3 = f2; // Error
I agree with this, make a function which validates the string is 20 chars and switches the type to be a nominal `IDString` instead of `string` - https://www.typescriptlang.org/play?q=439#example/nominal-typing
Something like this?