-
Notifications
You must be signed in to change notification settings - Fork 132
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
[Korean] Fix weird expressions like '_제네릭_' #171
Conversation
Translation of DOM Manipulation.mdtitle: DOM Manipulation translatable: trueDOM Manipulation
|
mode | input | output | Output File Extension |
---|---|---|---|
preserve |
<div /> |
<div /> |
.jsx |
react |
<div /> |
React.createElement("div") |
.js |
react-native |
<div /> |
<div /> |
.js |
react-jsx |
<div /> |
_jsx("div", {}, void 0); |
.js |
react-jsxdev |
<div /> |
_jsxDEV("div", {}, void 0, false, {...}, this); |
.js |
--jsx
Command line flag or tsconfig.json In a file jsx
You can set the mode through the corresponding options in .
*Consultation:
--jsxFactory
You can use the options to specify which JSX factory function to use when releasing React JSX. (The default isReact.createElement
)
as
operator
Here's how to write a type assertion:
var foo = <foo>bar;
This is a variable bar
price foo
Affirm to have a type.
TypeScript also uses angle brackets for assertions, so combining it with the syntax of JSX can cause difficulty in parsing certain things. As a result, TypeScript is .tsx
Does not allow angle bracket type affirmations in files.
This syntax is .tsx
Since it cannot be used in a file, the alternative type assertion operator as
must be used.
as
You can easily rewrite the above example using operators.
var foo = bar as foo;
as
The operator is .ts
and .tsx
Valid for all files of the format, the angle bracket type assertion style and behavior are the same.
Type checking
To understand type checking with JSX, you must first understand the difference between built-in and value-based elements.
<expr />
Given the JSX expression, expr
is an element built into the environment, such as the DOM environment. div
or span
) or a custom component.
Two reasons why this is important are:
- In React, built-in elements are strings (
React.createElement("div")
) but the components it produces are (React.createElement(MyComponent)
) not. - The type of attribute passed to a JSX element must be looked up differently.
The attributes of the built-in elements are Implicitly As it should be, components want to specify their own set of properties.
TypeScript uses this to distinguish between them. React-like rulesUse .
Built-in elements always start with lowercase letters, and value-based elements always start with uppercase letters.
Built-in elements
The built-in element is a special interface. JSX.IntrinsicElements
is looked up in .
Basically, if no interface is specified, it will proceed as is, and the built-in functions will not have type checking.
However, if this interface is which If the name of the built-in function is JSX.IntrinsicElements
It is queried by the properties in the interface.
For example:
declare namespace JSX {
interface IntrinsicElements {
foo: any;
}
}
<foo />; // 성공
<bar />; // 오류
In the example above, <foo />
works normally, <bar />
The JSX.IntrinsicElements
The error occurs because it is not specified in .
Note: As below
JSX.IntrinsicElements
You can also specify a catch-all string indexer in .
declare namespace JSX {
interface IntrinsicElements {
[elemName: string]: any;
}
}
Value-based elements
Value-based elements are simply looked up by identifiers within their scopes.
import MyComponent from "./myComponent";
<MyComponent />; // 성공
<SomeOtherComponent />; // 오류
There are two ways to define a value-based element:
- Functional Components (FC)
- Class Components
Since the two types of value-based elements are indistinguishable from JSX representations, TS first interprets the representation as a functional component using overload resolution. If successful, TS completes interpreting the expression on the declaration. If the value is not resolved to a functional component, TS interprets it as a class component. If that fails, TS reports an error.
Functional Components
As the name implies, a component has a first argument props
It is defined as a JavaScript function that is an object.
TS returns the type JSX.Element
must be assignable to .
interface FooProp {
name: string;
X: number;
Y: number;
}
declare function AnotherComponent(prop: { name: string });
function ComponentFoo(prop: FooProp) {
return <AnotherComponent name={prop.name} />;
}
const Button = (prop: { value: string }, context: { color: string }) => (
<button />
);
Functional components are JavaScript functions, so they can be overloaded:
interface ClickableProps {
children: JSX.Element[] | JSX.Element
}
interface HomeProps extends ClickableProps {
home: JSX.Element;
}
interface SideProps extends ClickableProps {
side: JSX.Element | string;
}
function MainButton(prop: HomeProps): JSX.Element;
function MainButton(prop: SideProps): JSX.Element {
...
}
Note: Functional components are known as stateless functional components (SFCs). Recent versions of React no longer consider functional components to be stateless.
SFC
Type and its aliasesStatelessComponent
is deprecated anymore.
Class Components
It is also possible to define a class component type.
But to do that, Element class type and _Element instance type_It's good to understand the two terms:
<Expr />
Given the , _Element Class Types_silver Expr
Type.
So, in the example above, MyComponent
If is an ES6 class, the type of that class is the constructor of the class and is global.
What if MyComponent
If is a factory function, the type of that class is that function.
Once the type of the class is determined, the instance type is determined by the creation of the class type or the combination of the return type of the calling signature (whichever of the two exists).
Again, for ES6 classes, the instance type must be the type of the instance of that class, and for factory functions, it must be the type of the value returned by the function.
class MyComponent {
render() {}
}
// 생성 시그니처 사용
var myComponent = new MyComponent();
// 요소 클래스 타입 => MyComponent
// 요소 인스턴스 타입 => { render: () => void }
function MyFactoryFunction() {
return {
render: () => {},
};
}
// 호출 시그니처 사용
var myComponent = MyFactoryFunction();
// 요소 클래스 타입 => FactoryFunction
// 요소 인스턴스 타입 => { render: () => void }
The element instance type is JSX.ElementClass
must be assignable to , or an error will be thrown.
By default JSX.ElementClass
The {}
However, it can be extended to restrict the use of JSX to only types that follow the appropriate interface.
declare namespace JSX {
interface ElementClass {
render: any;
}
}
class MyComponent {
render() {}
}
function MyFactoryFunction() {
return { render: () => {} };
}
<MyComponent />; // 성공
<MyFactoryFunction />; // 성공
class NotAValidComponent {}
function NotAValidFactoryFunction() {
return {};
}
<NotAValidComponent />; // 오류
<NotAValidFactoryFunction />; // 오류
Attribute Type Inspection
For attribute type checking, first _Element attribute type_You need to decide.
This is a slight difference between built-in and value-based elements.
For built-in elements, the element attribute type is JSX.IntrinsicElements
This is the type of my property.
declare namespace JSX {
interface IntrinsicElements {
foo: { bar?: boolean };
}
}
// 'foo'의 요소 속성 타입은 '{bar?: boolean}'
<foo bar />;
For value-based elements, this is slightly more complicated.
The element attribute type was previously determined Element Instance Type is determined by the property type of .
The properties to use are JSX.ElementAttributesProperty
is determined by:
It must be declared as a single property.
After that, use the name of that property.
Starting with TypeScript 2.8 JSX.ElementAttributesProperty
If you do not provide , you can use the type of the first parameter of the call to the class element or the functional component's name instead.
declare namespace JSX {
interface ElementAttributesProperty {
props; // 사용할 프로퍼티 이름 지정
}
}
class MyComponent {
// 요소 인스턴스 타입의 프로퍼티 지정
props: {
foo?: string;
};
}
// 'MyComponent'의 요소 속성 타입은 '{foo?: string}'
<MyComponent foo="bar" />;
Element attribute types are used for type checking of attributes in JSX.
Optional and essential properties are supported.
declare namespace JSX {
interface IntrinsicElements {
foo: { requiredProp: string; optionalProp?: number };
}
}
<foo requiredProp="bar" />; // 성공
<foo requiredProp="bar" optionalProp={0} />; // 성공
<foo />; // 오류, requiredProp이 누락됨
<foo requiredProp={0} />; // 오류, requiredProp은 문자열이여야 함
<foo requiredProp="bar" unknownProp />; // 오류, unknownProp는 존재하지 않음
<foo requiredProp="bar" some-unknown-prop />; // 성공, 'some-unknown-prop'는 유효한 식별자가 아니기 때문
Note: An identifier whose name of the attribute is valid (data-* attributes, etc.), if the element attribute type cannot be found, it is not considered an error.
Additional JSX.IntrinsicAttributes
Interfaces can specify additional properties for use of the JSX framework, which is not typically used as props or arguments to components. - For example React key
. Further, JSX.IntrinsicClassAttributes<T>
Generic types can also be specified in the same way as the types of additional attributes for class components (functional components are not). For that type, the generic parameter corresponds to a class instance type. In React, Ref<T>
Types of ref
Used to accept attributes. In general, if users of the JSX framework do not need to provide specific attributes to all tags, all properties of this interface should be optional.
The spread operator also works:
var props = { requiredProp: "bar" };
<foo {...props} />; // 성공
var badProps = {};
<foo {...badProps} />; // 오류
Child type checking
Starting with TypeScript 2.3, TS Children Introduced type checking. _child_Silver git _JSXExpressions_What you want to insert into this property _Element attribute type_is a special property of .
TS props To determine the name JSX.ElementAttributesProperty
Similar to using the TS, TS child To determine the name of props within JSX.ElementChildrenAttribute
Use .
JSX.ElementChildrenAttribute
must be defined as a single property.
declare namespace JSX {
interface ElementChildrenAttribute {
children: {}; // 사용할 자식의 이름을 지정
}
}
<div>
<h1>Hello</h1>
</div>;
<div>
<h1>Hello</h1>
World
</div>;
const CustomComp = (props) => <div>{props.children}</div>
<CustomComp>
<div>Hello World</div>
{"This is just a JS expression..." + 1000}
</CustomComp>
Like any other property_child_You can also specify the type of . For example, React typingIf you use , this will override the base type.
interface PropsType {
children: JSX.Element
name: string
}
class Component extends React.Component<PropsType, {}> {
render() {
return (
<h2>
{this.props.children}
</h2>
)
}
}
// OK
<Component name="foo">
<h1>Hello World</h1>
</Component>
// 오류: 자식은 JSX.Element의 배열이 아닌 JSX.Element 타입입니다
<Component name="bar">
<h1>Hello World</h1>
<h2>Hello World</h2>
</Component>
// 오류: 자식은 JSX.Element의 배열 또는 문자열이 아닌 JSX.Element 타입입니다
<Component name="baz">
<h1>Hello</h1>
World
</Component>
JSX Result Type
By default, the result of a JSX expression is any
Type.
JSX.Element
You can change it to that type through the interface.
However, information about elements, properties, or children within JSX cannot be retrieved through that interface.
The interface is a black box.
To Include an Expression
JSX uses braces to express expressions between tags ({ }
) to put it in.
var a = (
<div>
{["foo", "bar"].map((i) => (
<span>{i / 2}</span>
))}
</div>
);
The above code can't diverge a number through a string, so you'll get an error as a result.
preserve
The output using the options is as follows:
var a = (
<div>
{["foo", "bar"].map(function (i) {
return <span>{i / 2}</span>;
})}
</div>
);
React Integration
To use React and JSX together React typingmust be used.
This typing is appropriate for use with React. JSX
Define a namespace.
/// <reference path="react.d.ts" />
interface Props {
foo: string;
}
class MyComponent extends React.Component<Props, {}> {
render() {
return <span>{this.props.foo}</span>;
}
}
<MyComponent foo="bar" />; // 성공
<MyComponent foo={0} />; // 오류
JSX Configuration
There are various compiler flags used for JSX customization, which act as compiler flags and inline file-specific pragma. More details can be learned through the tsconfig reference page:
Translation of Iterators and Generators.md
title: Iterators and Generators
layout: docs
permalink: /ko/docs/handbook/iterators-and-generators.html
oneline: How Iterators and Generators work in TypeScript
translatable: true
Iterable
Symbol.iterator
Objects that have an implementation for a property are considered iterables.
Array
, Map
, Set
, String
, Int32Array
, Uint32Array
Built-in types such as , , etc. Symbol.iterator
The property is already implemented.
In an object Symbol.iterator
The function returns a list of values to iterate.
for..of
The door
for..of
Statements inside an object Symbol.iterator
Call the property to iterate over the iterable object.
Here's a simple array for..of
The loop is:
let someArray = [1, "string", false];
for (let entry of someArray) {
console.log(entry); // 1, "string", false
}
for..of
vs. for..in
The door
for..of
and for..in
The statements all iterate through the list, but the values that they repeat are different. for..in
is the object that repeats rudder Returns a list, but for..of
is the numeric property of the repeating object. value Returns a list.
The following is an example of this difference:
let list = [4, 5, 6];
for (let i in list) {
console.log(i); // "0", "1", "2",
}
for (let i of list) {
console.log(i); // "4", "5", "6"
}
Another difference is that for..in
It's just that it works on all these objects. So I use it as a way to check the properties of an object.
On the other hand for..of
focuses primarily on the values of iterable objects. Map
and Set
The same built-in object can access the stored value. Symbol.iterator
Implement the properties.
let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";
for (let pet in pets) {
console.log(pet); // "species"
}
for (let pet of pets) {
console.log(pet); // "Cat", "Dog", "Hamster"
}
Code Generation
ES5 and ES3 Targeting
If you are targeting an ES5 or ES3-compatible engine, the iterator is Array
It accepts only type values.
Symbol.iterator
Even if you implement a property, you can still use it in a non-Array value. for..of
Using a loop will result in an error.
The compiler is for..of
Simple about for
Create a loop, for example:
let numbers = [1, 2, 3];
for (let num of numbers) {
console.log(num);
}
The compiler generates the above code as follows:
var numbers = [1, 2, 3];
for (var _i = 0; _i < numbers.length; _i++) {
var num = numbers[_i];
console.log(num);
}
ECMAScript 2015 and higher version targeting
If you are targeting an ECMAScipt 2015-compliant engine, the compiler will target the built-in iterator implementation in the engine. for..of
Create a loop.
Translation of Decorators.md
title: Decorators
layout: docs
permalink: /ko/docs/handbook/decorators.html
oneline: TypeScript Decorators overview
translatable: true
Introduction
Further Reading:
A Complete Guide to TypeScript Decorators
With the introduction of classes in TypeScript and ES6, there are certain scenarios that require additional functionality to annotate or modify classes and their members.
Decorators provide a way to add annotations and meta-programming syntax to class declarations and members.
Decorator for JavaScript Step 2 Proposalis available as an experimental feature of TypeScript.
consultation Decorators are an experimental feature that may change in a future release.
To enable experimental support for decorators, use the command line or tsconfig.json
In experimentDecorators
You need to enable the compiler options:
Command Line:
tsc --target ES5 --experimentalDecorators
tsconfig.json:
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
Decorators
_Decorator_The Class Declaration, method, accessor, Properties or parameterA special kind of declaration that can be attached to .
The decorator is @expression
Use the format. Here expression
must be a function that is called at run time with information about the decorated declaration.
For example, decorators @sealed
Using as follows sealed
You can write a function.
function sealed(target) {
// 'target' 변수와 함께 무언가를 수행합니다.
}
Decorator Factories
If you want to change the way decorators are applied to declarations, you can create a decorator factory. _Decorator Factory_is simply a function that returns an expression that the decorator will call at run time.
You can create a decorator factory in the following ways:
function color(value: string) { // 데코레이터 팩토리
return function (target) { // 데코레이터
// 'target'과 'value' 변수를 가지고 무언가를 수행합니다.
};
}
Decorator Composition
You can apply multiple decorators to a declaration, as shown in the following example:
- For a single row:
// @experimentalDecorators
// @noErrors
function f() {}
function g() {}
// ---cut---
@f @g x
- For multiple rows:
// @experimentalDecorators
// @noErrors
function f() {}
function g() {}
// ---cut---
@f
@g
x
If multiple decorators are applied to a single declaration, Synthetic functions in mathematicsSimilar to .
Functions in this model _f_and _g_When synthesizing (f_∘_g)(x) The result of the synthesis of ) f(g(x)).
So when using multiple decorators in a single declaration in TypeScript, the following steps are taken:
- The representation of each decorator is evaluated from top to bottom.
- The result is then called as a function from the bottom up.
Decorator FactoryIf you use , you can observe this sequence of performances with the following example:
// @experimentalDecorators
function first() {
console.log("first(): factory evaluated");
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("first(): called");
};
}
function second() {
console.log("second(): factory evaluated");
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("second(): called");
};
}
class ExampleClass {
@first()
@second()
method() {}
}
This outputs the result to the console.
first(): factory evaluated
second(): factory evaluated
second(): called
first(): called
Decorator Evaluation
How to apply decorators to various declarations in a class is well defined as follows:
- method, accessor or _Property Decorator_followed by _Parameter Decorator_applies to each instance member.
- method, accessor or _Property Decorator_followed by _Parameter Decorator_applies to each static member.
- _Parameter Decorator_applies to the constructor.
- _Class Decorator_applies to the class.
Class Decorators
Class Decoratoris declared just before the class is declared.
Class decorators are applied to the class constructor and can be used to observe, modify, or replace class definitions.
Class decorators are used in declaration files or other surrounding contexts, such as 선언
class).
The expression of the class decorator is called as a function at run time with the constructor of the decorated class as the only argument.
When the class decorator returns a value, replace it with a constructor function where the class provides a declaration.
consultation If you choose to return a new constructor function, you must maintain the original prototype.
The logic of applying decorators at run time is to make this feature It doesn't do it for you.
Here's how to BugReport
The class decorator applied to the class (@sealed
) is an example.
// @experimentalDecorators
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
// ---cut---
@sealed
class BugReport {
type = "report";
title: string;
constructor(t: string) {
this.title = t;
}
}
Using the following function declaration: @sealed
You can define decorators.
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
When runs, it wraps both the constructor and the prototype.
Here's an example of how to override the constructor:
// @errors: 2339
// @experimentalDecorators
function reportableClassDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
reportingURL = "http://www...";
};
}
@reportableClassDecorator
class BugReport {
type = "report";
title: string;
constructor(t: string) {
this.title = t;
}
}
const bug = new BugReport("Needs dark mode");
console.log(bug.title); // Prints "Needs dark mode"
console.log(bug.type); // Prints "report"
// Note that the decorator *does not* change the TypeScript type
// and so the new property `reportingURL` is not known
// to the type system:
bug.reportingURL;
Method Decorators
_Method Decorator_is declared just before the method is declared.
The decorator is the method of Property Descriptor and can be used to observe, modify, or replace method definitions.
Method decorators can be used in declaration files, overloads, or other surrounding contexts, such as 선언
class).
The expression of the method decorator is called as a function at run time with the following three arguments:
- The constructor function of the class for a static member, or a prototype of the class for an instance member.
- Name of the member
- Member's Property Descriptor
consultation The script target is lower than 'ES5' Property Descriptor becomes 'undefined'.
If the method decorator returns a value, the method's Property Descriptor Used as:
consultation If the script target is lower than 'ES5', the return value is ignored.
Here's how to Greeter
A method decorator applied to a method in a class (@enumerable
) is an example:
// @experimentalDecorators
function enumerable(value: boolean) {
return function (target: any,propertyKey: string,descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
// ---cut---
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
Using the following function declaration: @enumerable
You can define decorators.
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
@enumerable(false)
The decorator is Decorator FactoryIs.
@enumerable(false)
When the decorator is called, the property descriptor enumerable
Modify the properties.
Accessor Decorators
_Accessor decorator_is declared just before the accessor declaration.
The accessor decorator is the accessor's _Property Descriptor_and can be used to observe, modify, or replace the definition of an accessor.
An accessor decorator is used in a declaration file or in another peripheral context, such as 선언
class).
consultation TypeScript for a single member
get
andset
Unable to decorate accessors.
Instead, all decorators of the member should be applied to the first accessor specified in document order.
Because, decorators are not individual declarations.get
andset
Combining Accessors _Property Descriptor_This is because it applies to .
The expression of the accessor decorator is called as a function at run time with the following three arguments:
- A constructor function of a class for a static member or a prototype of a class for an instance member
- Name of the member
- Member's Property Descriptor
consultation The script target is lower than 'ES5' _Property Descriptor_The
undefined
will be.
If the accessor decorator returns a value, the member's _Property Descriptor_Used as:
consultation If the script target is lower than 'ES5', the return value is ignored.
Here's how to Point
Accessor decorators applied to members of a class (@configurable
) is an example:
// @experimentalDecorators
function configurable(value: boolean) {
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
descriptor.configurable = value;
};
}
// ---cut---
class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@configurable(false)
get x() {
return this._x;
}
@configurable(false)
get y() {
return this._y;
}
}
Using the following function declaration: @configurable
You can define decorators:
function configurable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value;
};
}
Property Decorators
_Property Decorator_is declared just before the property declaration.
Property decorators can be used in declaration files or other surrounding contexts, such as 선언
class).
The expression of the property decorator is called as a function at run time with the following two arguments:
- A constructor function of a class for a static member or a prototype of a class for an instance member
- Name of the member
consultation In TypeScript
프로퍼티 데코레이터
Due to the way is initialized. _Property Descriptor_is not provided as an argument to the property decorator.
This is because when defining the members of the current prototype, there is no mechanism to describe the instance properties, and there is no way to observe or modify the initializers of the properties. The return value is also ignored.
Therefore, a property decorator can only be used to observe that a property with a particular name has been declared to a class.
You can use this information to record metadata about a property, as in the following example:
class Greeter {
@format("Hello, %s")
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
let formatString = getFormat(this, "greeting");
return formatString.replace("%s", this.greeting);
}
}
Using the following function declaration: @format
Decorators and getFormat
You can define a function:
import "reflect-metadata";
const formatMetadataKey = Symbol("format");
function format(formatString: string) {
return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
@format("Hello, %s")
The decorator is Decorator FactoryIs.
@format("Hello, %s")
When is called reflect-metadata
Library's Reflect.metadata
Use a function to add a metadata entry for a property.
getFormat
When called, it reads the metadata value of the type.
consultation In this example,
reflect-metadata
A library is required.
reflect-metadata
For more information about the library, see MetadataSee .
Parameter Decorators
_Parameter Decorator_is declared immediately before the parameter is declared.
The parameter decorator is applied to a function in the class constructor or method declaration.
Parameter decorators can be used in declaration files, overloads, or other peripheral contexts, such as 선언
class).
The expression of the parameter decorator is called as a function at runtime with the following three arguments:
- A constructor function of a class for a static member or a prototype of a class for an instance member
- Name of the member
- Ordinal index of a parameter in the function's parameter list
consultation A parameter decorator can be used to observe a parameter only when it is declared in a method.
The return value of the mezzanine decorator is ignored.
Here's how to BugReport
Parameter decorator (@required
) is an example:
// @experimentalDecorators
function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<any>) {}
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {}
// ---cut---
class BugReport {
type = "report";
title: string;
constructor(t: string) {
this.title = t;
}
@validate
print(@required verbose: boolean) {
if (verbose) {
return this.title;
} else {
return `type: ${this.type}\ntitle: ${this.title}`;
}
}
}
Using the following function declaration: @required
and @validate
You can define decorators.
// @errors: 2339 2339 2339
// @experimentalDecorators
// @emitDecoratorMetadata
import "reflect-metadata";
const requiredMetadataKey = Symbol("required");
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata( requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}
function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {
let method = descriptor.value!;
descriptor.value = function () {
let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);
if (requiredParameters) {
for (let parameterIndex of requiredParameters) {
if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {
throw new Error("Missing required argument.");
}
}
}
return method.apply(this, arguments);
};
}
@required
The decorator adds metadata entries that display the parameters as needed.
And then @validate
A decorator is a function that validates arguments before calling the original method, which is existing greet
Wrap the method.
consultation In this example,
reflect-metadata
A library is required.
reflect-metadata
For more information about the library, see [Metadata] See (#메타데이터-metadata).
Metadata
Some examples are Experimental metadata APIAdd a polyfill for reflect-metadata
Use a library.
This library is not yet part of the ECMAScript (JavaScript) standard.
However, when decorators are officially adopted as part of the ECMAScript standard, these extensions will be adopted.
You can install it via npm.
npm i reflect-metadata --save
TypeScript includes experimental support for emitting metadata of a specific type for declarations with decorators.
To enable this experimental support, use the command line ortsconfig.json
In emitDecoratorMetadata
You must set compiler options.
command line:
tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata
tsconfig.json:
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Once activated, reflect-metadata
Simply import the library and additional design-time type information is available at run time.
You can see this in the following example:
// @errors: 2339
// @emitDecoratorMetadata
// @experimentalDecorators
// @strictPropertyInitialization: false
import "reflect-metadata";
class Point {
constructor(public x: number, public y: number) {}
}
class Line {
private _start: Point;
private _end: Point;
@validate
set start(value: Point) {
this._start = value;
}
get start() {
return this._start;
}
@validate
set end(value: Point) {
this._end = value;
}
get end() {
return this._end;
}
}
function validate<T>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {
let set = descriptor.set!;
descriptor.set = function (value: T) {
let type = Reflect.getMetadata("design:type", target, propertyKey);
if (!(value instanceof type)) {
throw new TypeError(`Invalid type, got ${typeof value} not ${type.name}.`);
}
set.call(this, value);
};
}
const line = new Line()
line.start = new Point(0, 0)
// @ts-ignore
// line.end = {}
// Fails at runtime with:
// > Invalid type, got object not Point
The TypeScript compiler is @Reflect.metadata
Use decorators to inject design-time type information.
You can think of it as the same as the following TypeScript:
class Line {
private _start: Point;
private _end: Point;
@validate
@Reflect.metadata("design:type", Point)
set start(value: Point) {
this._start = value;
}
get start() {
return this._start;
}
@validate
@Reflect.metadata("design:type", Point)
set end(value: Point) {
this._end = value;
}
get end() {
return this._end;
}
}
consultation Decorator metadata is an experimental feature and may have major changes in future releases.
Translation of Declaration Merging.md
title: Declaration Merging
layout: docs
permalink: /ko/docs/handbook/declaration-merging.html
oneline: How merging namespaces and interfaces works
translatable: true
Introduction
Some of the unique concepts of TypeScript describe the shape of JavaScript objects at the type level.
A special example of TypeScript is the concept of 'merging declarations'.
Once you understand this concept, you will have many benefits when working with traditional JavaScript.
It will also open the door to advanced abstraction concepts.
To get back to the point, "merge declarations" means that the compiler combines two separate declarations declared with the same name into one definition.
This merged definition has the characteristics of both declarations in its original form. You can merge any number of declarations to be merged;
It does not restrict you to merging only two declarations.
Basic Concepts
In TypeScript, a declaration generates at least one entity in 3 groups of namespaces, types, or values.
Namespace-generated declarations use dot notation to generate a namespace with a name to access.
A type-generation declaration generates a type that is bound to a given name and expressed in the declared form.
Finally, the value-generation declaration produces output that you can see in JavaScript.
Declaration Type | Namespace | type | value |
---|---|---|---|
Namespace | X | X | |
class | X | X | |
Enumeration | X | X | |
interface | X | ||
Type aliases | X | ||
function | X | ||
variable | X |
Understanding the results produced by each declaration helps you understand the merged output when you merge declarations.
Merging Interfaces
The simplest and most common type of declarative merge is interface merge.
At the most basic level, merging mechanically combines the members of two declarations into a single interface of the same name.
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
}
let box: Box = { height: 5, width: 6, scale: 10 };
Non-function members of an interface must be unique.
If they are not unique, they must all be of the same type.
If an interface declares a function member of the same name, but with a different type, the compiler will throw an error.
For function members, each function member with the same name is treated as overloading of the same function.
It is also important to note that if you merge interface A with a later interface, the second interface will have a higher priority than the first.
For example:
interface Cloner {
clone(animal: Animal): Animal;
}
interface Cloner {
clone(animal: Sheep): Sheep;
}
interface Cloner {
clone(animal: Dog): Dog;
clone(animal: Cat): Cat;
}
The above three interfaces can be merged into a single declaration as follows:
interface Cloner {
clone(animal: Dog): Dog;
clone(animal: Cat): Cat;
clone(animal: Sheep): Sheep;
clone(animal: Animal): Animal;
}
Note that the elements in each group are in the same order, but the group itself will be placed in the first place as it is overloaded later.
There is an exception to this rule called specialized signatures.
What if unity If there is a parameter that is of type string literal (for example, if the string literal is not a union), the signature will be raised to the top of the merged overload list.
For example, the following interfaces are merged:
interface Document {
createElement(tagName: any): Element;
}
interface Document {
createElement(tagName: "div"): HTMLDivElement;
createElement(tagName: "span"): HTMLSpanElement;
}
interface Document {
createElement(tagName: string): HTMLElement;
createElement(tagName: "canvas"): HTMLCanvasElement;
}
Document
The result of the merged declaration of is as follows:
interface Document {
createElement(tagName: "canvas"): HTMLCanvasElement;
createElement(tagName: "div"): HTMLDivElement;
createElement(tagName: "span"): HTMLSpanElement;
createElement(tagName: string): HTMLElement;
createElement(tagName: any): Element;
}
Merging Namespaces
Like an interface, a namespace with the same name merges with a namespace member.
Because a namespace creates both a namespace and a value, you need to understand how the two merge.
To merge namespaces, type definitions are merged from the exported interfaces declared in each namespace, forming a single namespace with merged interface definitions inside.
To merge namespace values, the namespace value is expanded by adding the exported members of the second namespace to the first to the existing namespace, if there is already a namespace with the specified name in each declaration location.
These are examples: Animals
Merge Declaration of:
namespace Animals {
export class Zebra {}
}
namespace Animals {
export interface Legged {
numberOfLegs: number;
}
export class Dog {}
}
These include:
namespace Animals {
export interface Legged {
numberOfLegs: number;
}
export class Zebra {}
export class Dog {}
}
This model of namespace merging is a good starting point, but we need to understand what happens to unexported members.
Members that are not exported can only be viewed in the original namespace (the unmerged namespace). This means that after the merge, members merged into a different declaration will not be able to see the unexported members.
This is made more clear in the example below:
namespace Animal {
let haveMuscles = true;
export function animalsHaveMuscles() {
return haveMuscles;
}
}
namespace Animal {
export function doAnimalsHaveMuscles() {
return haveMuscles; // 오류, haveMuscles가 여기에 접근할 수 없기 때문에
}
}
haveMuscles
is not exported, so it shares the same unmerged namespace animalsHaveMuscles
Only functions can see this symbol.
doAnimalsHaveMuscles
functions, merged Animal
Even if you are a member of a namespace, you cannot see members that have not been exported.
Merging Namespaces with Classes, Functions, and Enums
Namespaces are flexible enough to merge with declarations of other types.
To do this, the namespace declaration must follow the declaration to be merged. The resulting declaration has properties of both declaration types.
TypeScript uses this to model patterns in JavaScript and other programming languages.
Merging Namespaces with Classes
This part refers to how to describe the inner classes.
class Album {
label: Album.AlbumLabel;
}
namespace Album {
export class AlbumLabel {}
}
The visibility rules for merged members are: Merging Namespaces As described in the session, AlbumLabel
You must export the class before you can see the merged class.
The end result is a class that is managed within another class.
You can also use namespaces to add more static members to an existing class.
In addition to the inner class pattern, you'll also be familiar with extending functions by creating them in JavaScript and adding properties.
TypeScript securely preserves and can be defined by merging declarations.
function buildLabel(name: string): string {
return buildLabel.prefix + name + buildLabel.suffix;
}
namespace buildLabel {
export let suffix = "";
export let prefix = "Hello, ";
}
console.log(buildLabel("Sam Smith"));
Similarly, the namespace can extend the enumeration of static members:
enum Color {
red = 1,
green = 2,
blue = 4,
}
namespace Color {
export function mixColor(colorName: string) {
if (colorName == "yellow") {
return Color.red + Color.green;
} else if (colorName == "white") {
return Color.red + Color.green + Color.blue;
} else if (colorName == "magenta") {
return Color.red + Color.blue;
} else if (colorName == "cyan") {
return Color.green + Color.blue;
}
}
}
Disallowed Merges
Not all merging is allowed in TypeScript.
Classes cannot be merged with other classes or variables.
For information about replacing merging classes, see Mixins in TypeScript You can see it in the section.
Module Augmentation
JavaScript does not support merging modules, but it can be patched by importing and updating existing objects.
Let's look at an easy observable example:
// observable.ts
export class Observable<T> {
// ... 연습을 위해 남겨둠 ...
}
// map.ts
import { Observable } from "./observable";
Observable.prototype.map = function (f) {
// ... 연습을 위해 남겨둠
};
This works fine in TypeScript, but the compiler Observable.prototype.map
I don't know about .
Module enrichment allows you to tell the compiler information:
// observable.ts
export class Observable<T> {
// ... 연습을 위해 남겨둠 ...
}
// map.ts
import { Observable } from "./observable";
declare module "./observable" {
interface Observable<T> {
map<U>(f: (x: T) => U): Observable<U>;
}
}
Observable.prototype.map = function (f) {
// ... 연습을 위해 남겨둠
};
// consumer.ts
import { Observable } from "./observable";
import "./map";
let o: Observable<number>;
o.map((x) => x.toFixed());
The module name is import
/export
is interpreted in the same way as the module specifier in .
For more information, see moduleSee .
The enriched declarations are then merged as if they were declared in the same file as the original.
However, keep in mind two limitations:
- You can't make a new top-level declaration to an enrichment -- you can only patch an existing declaration.
- Default exports cannot be enriched, only exports with a name (must be extended by that name,
default
is a reserved word - for more information #14080)
Global augmentation
Inside the module, you can add declarations to the global scope:
// observable.ts
export class Observable<T> {
// ... 연습을 위해 남겨둠 ...
}
declare global {
interface Array<T> {
toObservable(): Observable<T>;
}
}
Array.prototype.toObservable = function () {
// ...
};
Global reinforcement has the same behavior and limitations as module reinforcement.
Translation of Integrating with Build Tools.md
title: Integrating with Build Tools
layout: docs
permalink: /ko/docs/handbook/integrating-with-build-tools.html
oneline: How to use TypeScript with other build tools
Build Tools
Babel
installation
npm install @babel/cli @babel/core @babel/preset-typescript --save-dev
.babelrc
{
"presets": ["@babel/preset-typescript"]
}
Using the Command Line Interface
./node_modules/.bin/babel --out-file bundle.js src/index.ts
package.json
{
"scripts": {
"build": "babel --out-file bundle.js main.ts"
},
}
Using the Command Line Interface
npm run build
Browserify
installation
npm install tsify
Using the Command Line Interface
browserify main.ts -p [ tsify --noImplicitAny ] > bundle.js
Using the API
var browserify = require("browserify");
var tsify = require("tsify");
browserify()
.add("main.ts")
.plugin("tsify", { noImplicitAny: true })
.bundle()
.pipe(process.stdout);
For more information: smrq/tsify
Duo
installation
npm install duo-typescript
Using the Command Line Interface
duo --use duo-typescript entry.ts
Using the API
var Duo = require("duo");
var fs = require("fs")
var path = require("path")
var typescript = require("duo-typescript");
var out = path.join(__dirname, "output.js")
Duo(__dirname)
.entry("entry.ts")
.use(typescript())
.run(function (err, results) {
if (err) throw err;
// 컴파일된 결과를 출력 파일에 작성합니다
fs.writeFileSync(out, results.code);
});
For more information: frankwallis/duo-typescript
Grunt
installation
npm install grunt-ts
default gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
ts: {
default : {
src: ["**/*.ts", "!node_modules/**/*.ts"]
}
}
});
grunt.loadNpmTasks("grunt-ts");
grunt.registerTask("default", ["ts"]);
};
For more information: TypeStrong/grunt-ts
Gulp
installation
npm install gulp-typescript
default gulpfile.js
var gulp = require("gulp");
var ts = require("gulp-typescript");
gulp.task("default", function () {
var tsResult = gulp.src("src/*.ts")
.pipe(ts({
noImplicitAny: true,
out: "output.js"
}));
return tsResult.js.pipe(gulp.dest("built/local"));
});
For more information: ivogabe/gulp-typescript
Jspm
installation
npm install -g jspm@beta
Note: Currently, jspm's TypeScript support is 0.16beta.
For more information: TypeScriptSamples/jspm
Webpack
installation
npm install ts-loader --save-dev
The default webpack.config when using Webpack 2 .js
module.exports = {
entry: "./src/index.tsx",
output: {
path: '/',
filename: "bundle.js"
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".json"]
},
module: {
rules: [
// '.ts' 또는 '.tsx' 확장자를 가진 모든 파일은 'ts-loader'에 의해 처리됩니다.
{ test: /\.tsx?$/, use: ["ts-loader"], exclude: /node_modules/ }
]
}
}
The default webpack.config when using Webpack 1 .js
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js"
},
resolve: {
// '.ts'와 '.tsx'를 해석 가능한 확장자로 추가합니다.
extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
},
module: {
loaders: [
// '.ts' 또는 '.tsx' 확장자를 가진 모든 파일은 'ts-loader'에 의해 처리됩니다.
{ test: /\.tsx?$/, loader: "ts-loader" }
]
}
}
More about ts-loaderSee here.
Fall back:
MSBuild
Locally installed Microsoft.TypeScript.Default.props
(top) and Microsoft.TypeScript.targets
Update the project file to include the (bottom) file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- 하단에 default props 포함 -->
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props')" />
<!-- TypeScript 환경 설정 -->
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<TypeScriptRemoveComments>false</TypeScriptRemoveComments>
<TypeScriptSourceMap>true</TypeScriptSourceMap>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<TypeScriptRemoveComments>true</TypeScriptRemoveComments>
<TypeScriptSourceMap>false</TypeScriptSourceMap>
</PropertyGroup>
<!-- 하단에 default targets 포함 -->
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />
</Project>
For more information about MSBuild compiler option definitions: Setting compiler options for MSBuild projects
NuGet
- > Manage NuGet Packages
Microsoft.TypeScript.MSBuild
Search forInstall
Click- Once installed, rebuild it!
For more information, see Package Manager Dialogand Using NuGet and nightly buildsSee also
Translation of Configuring Watch.md
title: Configuring Watch
layout: docs
permalink: /ko/docs/handbook/configuring-watch.html
oneline: How to configure the watch mode of TypeScript
translatable: true
On how the compiler will monitor files and directories
- TypeScript 3.8+: Compiler flags
- Earlier version: Environment variables
to set it up.
Background
Compiler's --watch
The implementation is provided by node fs.watch
and fs.watchFile
Relies on , both of which have their pros and cons.
fs.watch
uses file system events to notify you of changes to the file/directory. However, it depends on the OS, the notifications are completely unbelievable, and they don't work as expected on many OSes. In addition, there may be a limit to the number of watchers that can be created (for example, linux), and programs with a large number of files can be used up very quickly. However, because this operation uses file system events, it does not involve much CPU cycle. Compilers are usually fs.watch
to monitor the directory. (e.g. the source directory contained in the config file, the directory where the module verification failed... etc.) to handle the missing precision in notifications about changes. However, the recursive watchdog feature is only supported on Windows and OSX. In other words, other OSes need something to replace the recursive attribute.
fs.watchFile
uses polling, so it includes CPU cycles. However, this is the most reliable mechanism to receive updates on file/directory status. Compilers are usually fs.watchFile
to monitor source files, configuration files, and missing files (see Missing files), which means that CPU usage depends on the number of files in the program.
Configuring file watching using a tsconfig.json
{
// Some typical compiler options
"compilerOptions": {
"target": "es2020",
"moduleResolution": "node"
// ...
},
// NEW: Options for file/directory watching
"watchOptions": {
// Use native file system events for files and directories
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
// Poll files for updates more frequently
// when they're updated a lot.
"fallbackPolling": "dynamicPriority"
}
}
You can read more about this in the release notes.
Environment Variables TSC*WATCHFILE
Configuring file watching using environment variable TSC*WATCHFILE
)
options | explanation |
---|---|
PriorityPollingInterval |
fs.watchFile , but uses different polling intervals for source files, config files, and missing files. |
DynamicPriorityPolling |
Use dynamic queues that poll frequently for files that are modified frequently, and poll unchanged files less frequently. |
UseFsEvents |
Using file system events fs.watch to be notified of file changes/creation/deletions. (fs.watch may work differently for different OSes.) For example. Linux has a limit on the number of watchers and fs.watch If you fail to create a watcher using , fs.watchFile You will use to create a watcher. |
UseFsEventsWithFallbackDynamicPolling |
This option is fs.watch If you fail to create a watcher using , except that polling is done via a dynamic queue. UseFsEvents It's similar to an option. (The thing about dynamic queues is DynamicPriorityPolling Described in Options.). |
UseFsEventsOnParentDirectory |
This option is fs.watch Watches the parent directory of the file (using file system events). However, CPU usage may increase and accuracy may decrease. |
default (no value specified) | Environment VariablesTSC*NONPOLLING*WATCHER If set to true, watches the parent directory of the file. (UseFsEventsOnParentDirectory Same as ).false fs.watchFile Use the 250ms It monitors all files with a time limit. |
Environment VariablesTSC*WATCHDIRECTORY
Configuring directory watching using environment variable TSC*WATCHDIRECTORY
)
On platforms that do not natively support recursive witness of directories on node, the directory witness feature is TSC*WATCHDIRECTORY
is supported by recursively creating a directory watcher for a subdirectory using the various options selected in . By default, on platforms that support recursive directory supervision (such as windows), the value of this environment variable is ignored.
options | explanation |
---|---|
RecursiveDirectoryUsingFsWatchFile |
fs.watchFile to watch for directories and subdirectories that are polling watches (with CPU cycles). |
RecursiveDirectoryUsingDynamicPriorityPolling |
Use a dynamic polling queue to poll for changes to directories and subdirectories. |
default (no value specified) | fs.watch to watch for directories and subdirectories. |
Translation of Understanding Errors.md
title: Understanding Errors
layout: docs
permalink: /ko/docs/handbook/2/understanding-errors.html
oneline: "How to see errors in TypeScript."
Understanding Errors
When TypeScript finds an error, it tries to explain in as much detail as possible what went wrong.
Because TypeScript's type system is structural, it can provide a detailed description of where the problem was found.
Terminology
Knowing the terms that often appear in error messages will help you understand them.
Assign (assignable to)
TypeScript is a type that can be replaced by another type when it can be replaced by another type. Can be assigned It is expressed as is.
In other words, 고양이
The 동물
Because it can replace 동물
to Can be assigned You.
As the name suggests, this relationship is t
and s
By examining the type of t = s;
Used to determine the validity of the assignment of
It is also used when checking in most places where the two types interact.
For example, when you call a function, the type of each argument is the type declared as a parameter. Can be assigned Must have.
Informally T is not assignable to S
If you say TypeScript, "_T
and S
is not compatible"_You just have to think that you are saying:
However, this is not the case Directional Keep in mind that this is a relationship: S
price T
Just because it can be assigned to T
price S
It cannot be assigned to .
Examples
Let's take a look at some examples of error messages and see what is happening.
Error Elaborations
Each error starts with a leading message and sometimes leads to more submessages.
You can think of each submessage as answering the "why?" question about the message above.
Let's take a look at how it actually works with a few examples.
The following example generates an error message that is longer than the example itself:
// @errors: 2322
let a: { m: number[] }
let b = { m: [""] }
a = b
On the last line, TypeScript found an error.
The logic for the error comes from the logic of checking that the assignment is healthy:
b
The type isa
Can it be assigned to a type? No. Why?- because
m
This is because the types of attributes are not compatible. Why? - because
b
ofm
Attribute (string[]
) isa
ofm
Attribute (number[]
) cannot be assigned. Why? - The type of an array of elements (
string
) to another type (number
) cannot be assigned.
Extra Properties
// @errors: 2322
type A = { m: number }
const a: A = { m: 10, n: "" }
Union Assignments
// @errors: 2322
type Thing = "none" | { name: string }
const a: Thing = { name: 0 }
Translation of Conditional Types.md
title: Conditional Types
layout: docs
permalink: /ko/docs/handbook/2/conditional-types.html
oneline: "Creating a type that behaves like an if statement in the type system."
The key to most useful programs is that the output must be determined by the input.
JavaScript programs aren't much different, but given the fact that you can easily check the type of a value, the decision on the output is also based on the type of input.
Conditional Type can help explain the relationship between input and output types.
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
type Example1 = Dog extends Animal ? number : string;
// ^?
type Example2 = RegExp extends Animal ? number : string;
// ^?
Conditional types are the ternary operator conditional statements in JavaScript (condition ? trueExpression : falseExpression
) has the same shape.
type SomeType = any;
type OtherType = any;
type TrueType = any;
type FalseType = any;
type Stuff =
// ---cut---
SomeType extends OtherType ? TrueType : FalseType;
extends
Based on , if the type on the left can be assigned to the right type, you get the first branch (the "true" value branch), otherwise you get the subsequent branch (the "false" value branch).
Dog extends Animal
Follow on number
I string
Aside from telling you if it's cognitive, in the example above, conditional types don't seem very useful!
But when used in conjunction with generics, conditional types have powerful forces.
For example, the following createLabel
Let's look at a function.
interface IdLabel {
id: number /* some fields */;
}
interface NameLabel {
name: string /* other fields */;
}
function createLabel(id: number): IdLabel;
function createLabel(name: string): NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel {
throw "unimplemented";
}
The overloads of createLabel represent a single JavaScript function based on the input type. Note the following:
- If the library has to create a similar kind of function throughout the API every time, it becomes cumbersome.
- We have 3 overloads, i.e. for each case positive Have a type (or each
number
andstring
) and the general case (string | number
) should have.createLabel
To deal with new types of , the number of overloads increases exponentially.
Instead, you can encode logic as a conditional type.
interface IdLabel {
id: number /* some fields */;
}
interface NameLabel {
name: string /* other fields */;
}
// ---cut---
type NameOrId<T extends number | string> = T extends number
? IdLabel
: NameLabel;
Using conditional types allows you to simplify up to a single function without overloading.
interface IdLabel {
id: number /* some fields */;
}
interface NameLabel {
name: string /* other fields */;
}
type NameOrId<T extends number | string> = T extends number
? IdLabel
: NameLabel;
// ---cut---
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
throw "unimplemented";
}
let a = createLabel("typescript");
// ^?
let b = createLabel(2.8);
// ^?
let c = createLabel(Math.random() ? "hello" : 42);
// ^?
Limiting to conditional types
Often, new information can be obtained from a conditional type of inspection.
Just as Type Guard narrows it down to more specific types, branching of the "true" value of conditional types can further limit generics depending on the type you are contrasting.
Consider the following example:
// @errors: 2536
type MessageOf<T> = T["message"];
In the example above, T
price message
I don't know if I have a property, so I'm getting an error in TypeScript.
T
You can limit the type of to make TypeScript no longer make errors.
type MessageOf<T extends { message: unknown }> = T["message"];
interface Email {
message: string;
}
type EmailMessageContents = MessageOf<Email>;
// ^?
but MessageOf
can receive any type, message
If there are no properties, never
Can I make it determined by type?
Here it is possible by moving the constraint to the outside and applying conditional types.
type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;
interface Email {
message: string;
}
interface Dog {
bark(): void;
}
type EmailMessageContents = MessageOf<Email>;
// ^?
type DogMessageContents = MessageOf<Dog>;
// ^?
Within the "true" value branch, TypeScript is T
price message
Have Properties to be You can tell.
In another example, if it is an array type, it will flatten it to the individual element types of the array, but if it is not an array type, it will remain the same. Flatten
You can create a type.
type Flatten<T> = T extends any[] ? T[number] : T;
// Extracts out the element type.
type Str = Flatten<string[]>;
// ^?
// Leaves the type alone.
type Num = Flatten<number>;
// ^?
Flatten
Given an array type, number
Through index access using string[]
You can get the element type of .
Otherwise, it returns the given type.
Infering within conditional types
We've seen above that you can extract a type using a conditional type with constraints.
This is a mundane task that makes conditional types easier.
The conditional type is infer
You can use keywords to deduce the types you are comparing from the "true" value branch.
For example Flatten
You can infer the element type without extracting it "directly" from to the indexed access type.
type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
Here in the "true" value branch T
Without having to present the element type of , infer
Keywords for New Generic Type Variables Item
I used it declaratively in .
This approach avoids the need to deeply analyze the structure of the type of person you are interested in.
infer
You can use keywords to use useful helper type aliases.
For example, let's look at a simple case for extracting a return type from a function type.
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
? Return
: never;
type Num = GetReturnType<() => number>;
// ^?
type Str = GetReturnType<(x: string) => string>;
// ^?
type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>;
// ^?
When inferring a type with multiple call signatures (like an overlot function type), last You'll deduce by the signature (perhaps, which is acceptable in all cases). You can't handle overloads based on a list of argument types.
declare function stringOrNum(x: string): number;
declare function stringOrNum(x: number): string;
declare function stringOrNum(x: string | number): string | number;
type T1 = ReturnType<typeof stringOrNum>;
// ^?
Decentralized conditional type
On top of a generic type, a conditional type encounters a union type, Decentralised It works.
For example, let's look at the following:
type ToArray<Type> = Type extends any ? Type[] : never;
ToArray
If you pass a union type to , the conditional type is applied to each member of the union.
type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr = ToArray<string | number>;
// ^?
StrArrOrNumArr
Here's how this works:
type StrArrOrNumArr =
// ---cut---
string | number;
Each member type of a union maps efficiently.
type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr =
// ---cut---
ToArray<string> | ToArray<number>;
And I get the result as follows:
type StrArrOrNumArr =
// ---cut---
string[] | number[];
In general, dispersion is the desired behavior. To avoid this behavior: extends
Just wrap the sides of the keyword in brackets.
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
// 'StrArrOrNumArr' is no longer a union.
type StrArrOrNumArr = ToArrayNonDist<string | number>;
// ^?
Translation of Everyday Types.md
title: Everyday Types
layout: docs
permalink: /ko/docs/handbook/2/everyday-types.html
oneline: "Primitive types of languages."
This chapter covers the most common types found in JavaScript code and explains how they are described in TypeScript and their respective counterparts.
We're not going to cover all of them in this article, and we'll cover more ways to create and use types in the chapters that follow.
Types are much more than just type notation _location_may appear in
In addition to learning about the type itself, we will also learn about the cases in which you refer to a type when you want to create a new struct.
Let's start by revisiting some of the most basic and common types you might encounter when writing JavaScript or TypeScript code.
These types are the key components that make up the more complex types that we will discuss later.
Raw Type: string
, number
and boolean
Three very common uses in JavaScript Primitive Typeto string
, number
and boolean
There is.
Each of these types has a corresponding type in TypeScript.
As you might expect, these types are used in JavaScript to match the value for each type. typeof
It has the same name that you get when you use the operator.
string
silver"Hello, world"
indicates a string value such asnumber
silver42
Represents a number such as . JavaScript does not have a separate runtime value for integers, soint
orfloat
There is no such thing as . All the numbers are simplynumber
Isboolean
silvertrue
andfalse
has only two values
String
,Number
,Boolean
Types such as (starting with uppercase letters) are valid types, but it is extremely rare to use such a special built-in type in your code. All the timestring
,number
,boolean
Use a type.
array
[1, 2, 3]
When specifying the type of an array, such as number[]
You can use syntax. This syntax can be used by any type (for example, string[]
is an array of strings).
The above type is Array<number>
It can be written in the same form as , and has the same meaning.
T<U>
For information about syntax, see Generic Let's find out more when dealing with .
[number]
has a completely different meaning. Tuple Type See section.
any
TypeScript is also any
, and can be used when you don't want a type checking error to occur because of a certain value.
What type of value is any
If so, any attribute can be accessed for that value (and the type of value returned is also any
), can be called as if it were a function, assign (receive), or do anything else that is syntactically valid.
let obj: any = { x: 0 };
// 아래 이어지는 코드들은 모두 오류 없이 정상적으로 실행됩니다.
// `any`를 사용하면 추가적인 타입 검사가 비활성화되며,
// 당신이 TypeScript보다 상황을 더 잘 이해하고 있다고 가정합니다.
obj.foo();
obj();
obj.bar = 100;
obj = "hello";
const n: number = obj;
any
Types can be useful when you don't want to redefine a long type just because of just one purpose of reassuring TypeScript that there is nothing wrong with a particular line in your code.
noImplicitAny
If TypeScript cannot deduce that type from the context for an untyped value, the compiler will any
Giving a type is the default behavior.
However, this situation is usually not preferred. because any
is because type checking is not done.
Compiler Flags noImplicitAny
Using implicitly any
Throws an error in all cases that you consider to be
Type notation for variables
const
, var
or let
When declaring a variable using the like, you can add type notation to explicitly specify the type of the variable, which is optional.
let myName: string = "Alice";
// ^^^^^^^^ 타입 표기
TypeScript is
int x = 0;
Do not use the notation of the expression "type to the left", as in .
Type notation is always the object of the type. On the back Location.
However, in most cases, type notation is not necessary.
If possible, TypeScript automatically uses the types in the code to _inference_Try to do it.
For example, the type of a variable is inferred based on the type of the supervalue of that variable.
// 타입 표기가 필요하지 않습니다. 'myName'은 'string' 타입으로 추론됩니다.
let myName = "Alice";
In most cases, you don't need to explicitly learn the rules of reasoning.
If you're just getting started with TypeScript, try using as little type notation as possible. You'll be surprised to learn that you don't need a lot of types to fully understand the flow of code.
function
Functions are the primary means of sending and receiving data in JavaScript.
TypeScript allows you to specify the input and output types of functions.
Parameter Type Notation
When you declare a function, you can specify the type after each parameter to declare the type of parameters that the function will allow.
The parameter type is written after the parameter name.
// 매개변수 타입 표기
function greet(name: string) {
// ^^^^^^^^
console.log("Hello, " + name.toUpperCase() + "!!");
}
If the parameter indicates a type, the arguments to that function are checked.
// @errors: 2345
declare function greet(name: string): void;
// ---셍략---
// 만약 실행되면 런타임 오류가 발생하게 됩니다!
greet(42);
Even if you don't specify the type in the parameter, TypeScript still checks whether the correct number of arguments are passed.
Return Type Notation
The return type can also be indicated.
The return type is written after the parameter list.
function getFavoriteNumber(): number {
// ^^^^^^^^
return 26;
}
As with the type notation of a variable, it is common to not have to specify the return type. Because TypeScript is contained in that function. return
This is because we will infer the return type based on the statement.
The type notation used in the example above doesn't mean much.
Sometimes there is code that performs explicit typing for documentation purposes, to prevent incorrect modifications to the code, or out of a very personal preference.
Anonymous functions
Anonymous functions are a bit different from function declarations.
If you can figure out how a function will be called by looking where it is in your code, TypeScript automatically assigns a type to the function's parameters.
Below is an example.
Here's an example:
// @errors: 2551
// 아래 코드에는 타입 표기가 전혀 없지만, TypeScript는 버그를 감지할 수 있습니다.
const names = ["Alice", "Bob", "Eve"];
// 함수에 대한 문맥적 타입 부여
names.forEach(function (s) {
console.log(s.toUppercase());
});
// 화살표 함수에도 문맥적 타입 부여는 적용됩니다
names.forEach((s) => {
console.log(s.toUppercase());
});
parameter s
Despite the fact that the type is not specified in , TypeScript is s
With the deduced type of array to find out the type of forEach
We used the type of the function.
The process is _Give contextual types_because the function is executed _context_to know what type the function should have.
Similar to the rules of reasoning, you don't have to explicitly learn how this process works, but if this is the case, _What actually happens_This will help you distinguish between cases where type notation is unnecessary.
Examples of how the context in which a value occurs affects the type of that value will be explored later.
Object Type
Except for primitive types, the types encountered the most are _Object Type_Is.
An object is a JavaScript value that has properties, which is the case in most cases!
To define an object type, simply list the properties of the object and the types of each property.
For example, the function below is taking an object that appears to be coordinates as an argument.
// 매개 변수의 타입은 객체로 표기되고 있습니다.
function printCoord(pt: { x: number; y: number }) {
// ^^^^^^^^^^^^^^^^^^^^^^^^
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });
The parameters above are x
and y
is denoted as a type of two properties, both of which are number
Type.
When you distinguish between each property ,
or ;
, and the notation of the last delimiter is optional.
The type notation of each property is also optional.
If you do not specify a type, the property is any
Consider it a type.
Optional Properties
An object type is a type of some or all of the properties that is optional, that is, _Optional_can be specified as:
Property name followed by ?
You can add .
function printName(obj: { first: string; last?: string }) {
// ...
}
// 둘 다 OK
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });
In JavaScript, when you access a property that doesn't exist, you don't get a run-time error. undefined
You get a value.
Because of this, the Optional Properties Read When, prior to using that value undefined
You need to check whether it is or not.
// @errors: 2532
function printName(obj: { first: string; last?: string }) {
// 오류 - `obj.last`의 값이 제공되지 않는다면 프로그램이 멈추게 됩니다!
console.log(obj.last.toUpperCase());
if (obj.last !== undefined) {
// OK
console.log(obj.last.toUpperCase());
}
// 최신 JavaScript 문법을 사용하였을 때 또 다른 안전한 코드
console.log(obj.last?.toUpperCase());
}
Union Type
TypeScript's type system allows you to create new types using a variety of operators based on existing types.
Now that you know how to use some types, you can use them In combination It's time to try it out in an interesting way.
To Define Union Types
The first way to combine types is to Union It's about using types.
A union type is created using two or more different types, and the value of a union type is one of the types used for type combinations. _Anything One_can be had as a type.
Each type used in the combination is a union type _member_Call.
Let's write a function that can receive a string or a number.
// @errors: 2345
function printId(id: number | string) {
console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// 오류
printId({ myID: 22342 });
Using Union Types
Values that match the union type Provided by It's that simple. You can provide a type that corresponds to one of the members of the union type.
A value that is of type Union is in the code When it exists, how do I use it?
When dealing with a union in TypeScript, the union type all Allowed only when the operation is valid for a member.
For example string | number
For a union type named string
You cannot use methods that are only valid for types.
// @errors: 2339
function printId(id: number | string) {
console.log(id.toUpperCase());
}
To solve this, use Union in your code Narrow This is the same as what happens in JavaScript without type notation.
_Narrow_An issue occurs when TypeScript can infer a value to a more specific type based on the code structure.
For example, TypeScript is only string
Value only typeof
As the result of the operation "string"
I know you can have .
function printId(id: number | string) {
if (typeof id === "string") {
// 이 분기에서 id는 'string' 타입을 가집니다
console.log(id.toUpperCase());
} else {
// 여기에서 id는 'number' 타입을 가집니다
console.log(id);
}
}
Another example is Array.isArray
is to use a function like .
function welcomePeople(x: string[] | string) {
if (Array.isArray(x)) {
// 여기에서 'x'는 'string[]' 타입입니다
console.log("Hello, " + x.join(" and "));
} else {
// 여기에서 'x'는 'string' 타입입니다
console.log("Welcome lone traveler " + x);
}
}
else
Please note that branch statements do not need to be processed separately. x
The type of string[]
If not, x
The type of must be string
It will be.
Sometimes all members of a union may have something in common.
For example, arrays and strings are both slice
Embedding methods.
If all members of a union have a property in common, they can use it without narrowing it.
// 반환 타입은 'number[] | string'으로 추론됩니다
function getFirstThree(x: number[] | string) {
return x.slice(0, 3);
}
Union is semantically union, which actually means that the Union type is the property of _intersection_It seems to point to and can feel confusing.
This is no coincidence. _Union_The name comes from type theory.
number | string
Union Types have their own types About the values It is constructed by taking a union.
Given two sets and attributes for each set, the two sets of _Union_There are a number of characteristics of each _intersection_Please note that only applies.
For example, let's say you have tall people wearing hats in one room and people in the other room who speak Spanish. If you combine the two rooms, all What we can know about people is that everyone must wear a hat.
Type aliases
Until now, when using object types and union types, they were written directly.
This is convenient, but there are times when you want to reuse the same type more than once or call it by another name.
_Type aliases_exists for this very case, _type_for _name_to provide.
The syntax of the type alias is as follows:
type Point = {
x: number;
y: number;
};
// 앞서 사용한 예제와 동일한 코드입니다
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
Type aliases allow you to give new names to any type, not just object types.
For example, you can also give a type alias to a union type as shown below.
type ID = number | string;
The type alias is merely Please note that it is nothing more than an alias. In other words, using type aliases does not create "multiple versions" that are distinct from each other for the same type.
To use an alias is to create a new separately named type.
In other words, the code below looks like it's wrong. Can be seen However, this is normal in TypeScript because each type is an alias for the same type.
declare function getInput(): string;
declare function sanitize(str: string): string;
// ---cut---
type UserInputSanitizedString = string;
function sanitizeInput(str: string): UserInputSanitizedString {
return sanitize(str);
}
// 보안 처리를 마친 입력을 생성
let userInput = sanitizeInput(getInput());
// 물론 새로운 문자열을 다시 대입할 수도 있습니다
userInput = "new input";
interface
_Interface Declaration_is another way to create object types.
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
As with the use of type aliases, the example code above behaves as if it were using an arbitrary anonymous object with no type.
TypeScript is only printCoord
of the value passed to _rescue_I'm only interested. In other words, it only depends on whether you have the predicted properties.
As such, the fact that we are only interested in the structure and capabilities of a type means that TypeScript Structured That's why it's called a type system.
Differences between type aliases and interfaces
The interface is very similar to the type alias, and in most cases you are free to choose between the two to use.
interface
Most of the functions that it has are type
The same is available in . The most important difference between the two is that types cannot be opened to add new properties, whereas interfaces can always be extended.
인터페이스 |
타입 |
---|---|
인터페이스 확장하기
|
교집합을 통하여 타입 확장하기
|
기존의 인터페이스에 새 필드를 추가하기
|
타입은 생성된 뒤에는 달라질 수 없다
|
The above concepts will be taught in more detail in the following chapters, so don't worry if you don't understand them well now.
- In versions prior to TypeScript 4.2, the type alias name is used in the error message It may appear and, sometimes appears on behalf of an equivalent anonymous type (which in some cases may or may not be desirable). The interface always appears in the error message.
- The type alias is it cannot be included in a declaration merge but interfaces can be included.
- The interface is It is only used to declare the shape of an object, and cannot be used to give aliases to existing primitive types.
- The name of the interface is Always as it is An error message appears. However, this is only This is only true when that interface is used by name in the code.
In most cases, you can choose between interface and type according to your personal preferences, and TypeScript will suggest a different choice if necessary. If you're not sure, first of all interface
When using and subsequently experiencing problems. type
Please use the
Type affirmation
Sometimes there are cases where you know more information about the type of any value than TypeScript.
For example, in code document.getElementById
If is used, TypeScript is used at this time. HTMLElement
During _something_While you can only see that is returned, you can always use the ID used on the page. HTMLCanvasElement
You may already know that is returned.
In this case, _Type affirmation_allows you to be more specific about the type.
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
As with type notation, type affirmations are removed by the compiler and do not affect the run-time behavior of your code.
The use of angle brackets is also a way to use (the code .tsx
if it is not a file) and it has the same meaning.
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");
Remember: Type assertions are removed at compile time, so checks related to type assertions are not made during runtime.
Even if the type affirmation is incorrect, an exception is thrown, ornull
This will not be created.
In TypeScript, More specific or Less specific Only type affirmations that convert to version types are allowed.
These rules prevent the following "impossible" coercion:
// @errors: 2352
const x = "hello" as number;
This rule is sometimes overly conservative, disallowing coercion that can be complex but valid.
In this case, you can use two assertions. any
(or as we will introduce later) unknown
), and then to the type you want.
declare const expr: any;
type T = { a: 1; b: 2; c: 3 };
// ---cut---
const a = (expr as any) as T;
Literal Type
string
and number
In addition to common types such as, Specific You can specify string and numeric values in the type position.
To understand this, think of the different methods provided for variable declarations in JavaScript. var
and let
You can change the kind of value that can be stored in both variables. const
This is not possible. These features are reflected in the way TypeScript generates types for literal values.
let changingString = "Hello World";
changingString = "Olá Mundo";
// 변수 `changingString`은 어떤 문자열이든 모두 나타낼 수 있으며,
// 이는 TypeScript의 타입 시스템에서 문자열 타입 변수를 다루는 방식과 동일합니다.
changingString;
// ^?
const constantString = "Hello World";
// 변수 `constantString`은 오직 단 한 종류의 문자열만 나타낼 수 있으며,
// 이는 리터럴 타입의 표현 방식입니다.
constantString;
// ^?
Literal types are not very significant in themselves.
// @errors: 2322
let x: "hello" = "hello";
// OK
x = "hello";
// ...
x = "howdy";
A variable that can only have one value is useless!
But literals with Union When used together, you will be able to express more useful concepts. For example, you might define a function that can accept only certain kinds of values as arguments.
// @errors: 2345
function printText(s: string, alignment: "left" | "right" | "center") {
// ...
}
printText("Hello, world", "left");
printText("G'day, mate", "centre");
Numeric literal types can also be used in the same way.
function compare(a: string, b: string): -1 | 0 | 1 {
return a === b ? 0 : a > b ? 1 : -1;
}
Of course, it can also be used with non-literal types.
// @errors: 2345
interface Options {
width: number;
}
function configure(x: Options | "auto") {
// ...
}
configure({ width: 100 });
configure("auto");
configure("automatic");
There is another literal type. That's the bull literal type.
There are only two types of bull literals, which, as you might expect, true
and false
Is.
boolean
The type itself is in fact just true | false
An alias of type Union.
Literal inference
When you initialize a variable with an object, TypeScript assumes that the object's properties may subsequently change its value.
For example, let's say you write code like this:
declare const someCondition: boolean;
// ---cut---
const obj = { counter: 0 };
if (someCondition) {
obj.counter = 1;
}
Existing Value 0
In the field that was 1
When you assign , TypeScript does not consider it an error.
To put it another way: obj.counter
Be sure to number
Must have a type, 0
It means you can't have a literal type. Because the type is Read and writing This is because it is used to determine both behaviors.
The same applies to strings.
// @errors: 2345
declare function handleRequest(url: string, method: "GET" | "POST"): void;
// ---cut---
const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);
In the example above, req.method
The string
Not deduced as, "GET"
is not deduced as. req
The timing of its creation and handleRequest
Code evaluation can occur any amount of time between the invocation points of , at which point req.method
at "GUESS"
Because a new string such as may be assigned, TypeScript determines that there is an error in the above code.
There are two ways to resolve these cases:
-
You can change the way you reason by adding type affirmations in either location.
declare function handleRequest(url: string, method: "GET" | "POST"): void; // ---cut--- // 수정 1: const req = { url: "https://example.com", method: "GET" as "GET" }; // 수정 2 handleRequest(req.url, req.method as "GET");
Revision 1 is
req.method
There is always Literal Type"GET"
It intends to win, and accordingly in the corresponding field"GUESS"
We will prevent the assignment of a value such as " in the first place".
Revision 2 states that "For some reason,req.method
price"GET"
knows that you have a value." -
as const
You can use to convert an entire object to a literal type.declare function handleRequest(url: string, method: "GET" | "POST"): void; // ---cut--- const req = { url: "https://example.com", method: "GET" } as const; handleRequest(req.url, req.method);
as const
Suffixes are common const
works similarly to , for all properties of that object. string
or number
Ensures that values of literal types rather than more general types such as are assigned.
null
and undefined
There are two primitive values in JavaScript that point to empty or uninitialized values. straight null
and undefined
Is.
TypeScript has two names with the same name corresponding to each value. _type_This exists. The way each type works is strictNullChecks
It depends on whether the option is set or not.
strictNullChecks
When is not set
strictNullChecks
price If it's not set, what value is null
or undefined
Even if it could, you can access that value as usual, null
and undefined
can be assigned to any type of variable.
This is similar to how languages that do not do null checking (C#, Java, etc.) behave.
The lack of null checking is also a major cause of bugs. For no apparent reason, throughout the code strictNullChecks
It is always recommended that you set the options.
strictNullChecks
When set up
strictNullChecks
price If it is set, what value is null
or undefined
When , you should test that value before you use a method or property with that value.
Before using optional properties undefined
As with checking whether or not _Narrow_Through null
You can perform a check on any value that can be.
function doSomething(x: string | undefined) {
if (x === undefined) {
// 아무 것도 하지 않는다
} else {
console.log("Hello, " + x.toUpperCase());
}
}
Non-null assertion operator (suffix !
)
In TypeScript, the type is set up without explicit checking. null
and undefined
Provides a special syntax to remove .
After the expression !
When you create , its value is null
or undefined
is to affirm that it is not type.
function liveDangerously(x?: number | undefined) {
// 오류 없음
console.log(x!.toFixed());
}
Like other type assertions, this syntax does not change the run-time behavior of the code, so !
The operator must have that value null
or undefined
price Is not It should only be used.
Enumeration
An enumeration is a feature that TypeScript adds to JavaScript, where any value is _A set of constants with names_The ability to restrict it to one of the values that belong to . Unlike most TypeScript features, this feature has a type level in JavaScript. Is not, a feature that is added at the language and runtime level. So you probably need to know what an enum is, but if you don't have a clear idea of how to use it, it's a good idea to put it on hold for actual use. To learn more about enumerations Enumeration documentsPlease read on.
Primitive types that are not often used
In addition to the aforementioned types, we will cover the rest of the JavaScript primitive types that exist in the type system.
Of course, I'm not going to go into depth here.
bigint
Since ES2020, primitive types have been added to JavaScript to handle very large integers. straight bigint
Is.
// @target: es2020
// BigInt 함수를 통하여 bigint 값을 생성
const oneHundred: bigint = BigInt(100);
// 리터럴 구문을 통하여 bigint 값을 생성
const anotherHundred: bigint = 100n;
For more information about BigInt, see TypeScript 3.2 Release NotesYou can check it out here.
symbol
symbol
is a primitive type that can be used to generate globally unique reference values. Symbol()
You can create it through a function.
// @errors: 2367
const firstName = Symbol("name");
const secondName = Symbol("name");
if (firstName === secondName) {
// 절대로 일어날 수 없습니다
}
For more information about Symbol, see Symbol DocumentsYou can check it out here.
Translation of Basics.md
title: The Basics
layout: docs
permalink: /ko/docs/handbook/2/basic-types.html
oneline: "The first step in learning TypeScript: Basic types."
preamble: >
Welcome to the first chapter of the Handbook, and if you're new to TypeScript, you're welcome to the ''Get StartedI recommend reading one of the guide documents first.
Every value in JavaScript has its own set of different actions, which can be verified by executing various operations.
This may sound a bit abstract, as a simple example. message
Let's take a look at some of the operations that you can perform on a variable named .
// 'message'의 프로퍼티 'toLowerCase'에 접근한 뒤
// 이를 호출합니다
message.toLowerCase();
// 'message'를 호출합니다
message();
Analyzing the above code, first of all, the first line of executable code is toLowerCase
accesses the property and calls it.
On the second line, message
You are trying to call directly.
but message
If you don't know what the value of is—in general, it is—I can't say for sure what the result of the execution of the above code will be.
The behavior of each operation is completely dependent on what value you had in the first place.
message
is callable?toLowerCase
Do you have a property called ?- If you have,
toLowerCase
Is it also callable? - If both values are callable, what does each return?
These are common questions that we struggle with when writing code in JavaScript, and we always hope that we don't miss every detail about them.
message
Let's say is defined as below.
const message = "Hello World!";
As you might have guessed, here message.toLowerCase()
If we run , we will get a value where the same string consists of only lowercase letters.
So what about the second line of code we saw earlier?
If you're familiar with JavaScript, you know it won't run with exceptions.
TypeError: message is not a function
It would be great if we could prevent mistakes like this in advance.
The JavaScript runtime uses the value of the value to determine what it should do when the code is executed. type, that is, to see what actions and abilities the value has.
This is what it is TypeError
implies that. In the example above, the string is "Hello World"
is saying that cannot be called as a function.
Some values, such as string
and number
For values of primitive types such as , typeof
Operators allow you to know the type of each value at the time of execution.
However, for other values, such as function values, there is no mechanism at which the type of that value is executed, as in the aforementioned manner.
For example, consider the following function:
function fn(x) {
return x.flip();
}
Looking at the above code, the object passed as an argument is a callable property. flip
Only by reading the code that the above function will work well if we have You can tell. But JavaScript doesn't know what we know about this information while the code is running.
In pure JavaScript fn
The only way to know what is doing with a particular value is to call it and see what happens.
Behavior like this makes it difficult to predict before the code runs. In other words, it's hard to know while you're writing the code what the behavior results will be.
In this respect, _type_What value is Iran fn
A concept that can be passed to , and which explains that any value will fail to execute.
JavaScript is only Dynamic You only provide types, and you have to run the code to see what happens.
The alternative to this is Static Executing code using the type system ago It's about making predictions about your code.
Static type checking
Seen string
Obtained when you wanted to call as a function. TypeError
Let's return to the story of .
Most people I don't want to see any errors when I run the code. It is considered a bug!
And when we write new code, we do our best not to create new bugs.
Here, if you add a little code, save the file, and then immediately notice the error when you run the code again, you can quickly isolate the problem. But that's not always the case.
If you haven't tested the feature enough, you may not be able to spot any potential errors!
Or, even if you're lucky enough to find an error, you may end up going through a sizable refactoring and unintentionally digging deep into your code as you add new code.
Ideally, to run the code ago It would be great if you had a tool that could detect these bugs in advance.
That's what a static type checker like TypeScript does.
_Static type system_describes the form and behavior of the values used in the programs we have written.
Type checkers like TypeScript take advantage of this information to let us know when a program isn't working properly.
// @errors: 2349
const message = "hello!";
message();
If you run the last example above with TypeScript, you'll first check for error messages before the code runs.
Non-exception execution failure
So far, we've covered runtime errors. This is the case if the JavaScript runtime tells us directly that something is strange.
These errors can be attributed to how JavaScript should respond when an unexpected problem occurs. ECMAScript SpecificationThis is because you provide an explicit procedure in .
For example, according to the specification, an error occurs if you attempt to make a call to something that is not callable.
This may sound like a "natural move", but someone might think that they should also throw an error when they try to access a property that doesn't exist in the object.
But instead, JavaScript reacts quite differently. undefined
Returns the .
const user = {
name: "Daniel",
age: 26,
};
user.location; // undefined 를 반환
Ultimately, a static type system should let you know if any code is "valid" JavaScript code that does not cause an error, if it is considered an error within the static type system.
In TypeScript, the code below is location
This will raise an error that it is not defined.
// @errors: 2339
const user = {
name: "Daniel",
age: 26,
};
user.location;
Although sometimes this will cost you flexibility in expression, the purpose of doing so is not an explicit bug, but rather to catch cases that are reasonably considered bugs.
And TypeScript has these seemingly invisible bugs. Pretty much Grab it.
For example, typos,
// @noErrors
const announcement = "Hello World!";
// 바로 보자마자 오타인지 아실 수 있나요?
announcement.toLocaleLowercase();
announcement.toLocalLowerCase();
// 아마 아래와 같이 적으려 했던 것이겠죠...
announcement.toLocaleLowerCase();
Uncalled functions,
// @noUnusedLocals
// @errors: 2365
function flipCoin() {
// 본래 의도는 Math.random()
return Math.random < 0.5;
}
Or a basic logic error, etc.
// @errors: 2367
const value = Math.random() < 0.5 ? "a" : "b";
if (value !== "a") {
// ...
} else if (value === "b") {
// 이런, 이 블록은 실행되지 않겠군요
}
Types as programming tools
TypeScript catches bugs when we make mistakes in our code.
That's good, but TypeScript is Going further from here, It prevents us from making mistakes the very moment we make them.
The Type Checker has relevant information so that we can check whether we are accessing the correct properties on a variable or other property.
Using this information, the Type Checker will show us which properties we can use. _proposition_You will be able to do it.
This means that TypeScript can be used to modify code, provide error messages as we type code, or provide code completion.
This is a common reference when discussing tools in TypeScript.
// @noErrors
// @esModuleInterop
import express from "express";
const app = express();
app.get("/", function (req, res) {
res.sen
// ^|
});
app.listen(3000);
TypeScript takes programming tools seriously, and this includes a lot more than just code completion and error message features.
Code editors that support TypeScript provide "Quick Fixes" that automatically fix errors, refactoring your code with ease, useful navigation to quickly jump to the definition of a variable, and searching for all references to a given variable.
All of these features are based on Type Checker and operate entirely cross-platform, Your favorite code editor supports TypeScriptThe probability of doing so is high.
tsc
, TypeScript compiler
So far, we've talked about type checking, but it's still a type _Checker_I didn't use .
Our New Friends tsc
Let's say first hello to the TypeScript compiler.
First, let's install it using npm.
npm install -g typescript
If you run the above code, you will see the TypeScript compiler
tsc
is installed globally.
tsc
Localnode_modules
If you want to run it from a packagenpx
Or you can use a similar tool.
Now go to the empty folder and click on the first TypeScript program, hello.ts
Let's write .
// 세상을 맞이하세요.
console.log("Hello world!");
Note that no underscores are drawn in the code. This "hello world" program looks exactly like a "hello world" program written in JavaScript.
And now typescript
Installed with the package tsc
Run a command to perform type checking.
tsc hello.ts
Voila!
Wait, exactly _what_You mean you came out with this "voila"?
tsc
but nothing happened!
Well, there was no type error, so nothing was going to be reported, so there was no output on the console.
But if we check again, we can see that instead of file I got the output.
Looking at the current directory, hello.ts
Next to the file hello.js
You can see that the file exists.
This tsc
Our hello.ts
The file is a JavaScript file Compile or _metamorphosis_One deliverable.
And if you check that content, TypeScript will .ts
After processing the file, you can see what it spit out.
// 세상을 맞이하세요.
console.log("Hello world!");
In the above case, TypeScript had very little to transform, so it yielded the same output that we wrote in the first place.
The compiler attempts to produce code that is as clean and readable as if it were written by a human.
Of course, it's not always easy, but TypeScript does the indentation consistently, takes into account that the code is written across multiple lines, and places the comments that are written around the code well.
If there is a type checking error Given What?
hello.ts
Let's rewrite .
// @noErrors
// 아래는 실무 수준에서 범용적으로 쓰이는 환영 함수입니다
function greet(person, date) {
console.log(`Hello ${person}, today is ${date}!`);
}
greet("Brendan");
Here tsc hello.ts
Keep in mind that if you run again, you'll get an error on the command line!
Expected 2 arguments, but got 1.
TypeScript is greet
You're telling me that I forgot to pass arguments to the function, and it really is.
So far, we've only written standard JavaScript, but we've still been able to spot problems in our code through type checking.
Thanks, TypeScript!
Throwing an error
I don't know if you noticed it in the example I looked at earlier, hello.js
The contents of the file have been modified once again.
When you open the file, you'll see that it's practically the same as the code file used as input.
Look at our code tsc
may seem a bit surprising given that has caused the error, but it's behavior based on one of the core values of TypeScript. That's right, in most cases You I think you know better than TypeScript.
As mentioned earlier, type checking for code restricts the actions that a program can execute. Therefore, there are some trade-offs and compromises in the range of behavior that type checking allows or restricts.
In most cases, the problem does not occur, but there are also scenarios where type checking is a hindrance.
For example, consider a case where you encounter a type checking error while migrating code written in JavaScript to TypeScript.
Eventually, we'll modify the code to make it pass type checking, but the truth is that the original JavaScript code was already working fine!
Is there a reason why the conversion to TypeScript should interrupt the execution of the code?
So TypeScript doesn't disturb you.
Of course, over time, you may want to be more defensive about mistakes and have TypeScript behave more rigorously.
In this case, --noEmitOnError
You can do so by using the compiler option.
hello.ts
After modifying the file, use the flag option above tsc
Try running .
tsc --noEmitOnError hello.ts
hello.js
You can see that none of is modified.
Explicit types
So far it is still up to TypeScript person
or date
didn't tell you what it was.
Modify the code so that TypeScript person
Two string
and date
price Date
Let them know it should be an object.
In addition date
of toDateString()
Let's use the method.
function greet(person: string, date: Date) {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
We just had person
and date
as opposed to _Type notation_By doing the greet
Described the types of values that can be used together when is called.
The signature is "greet
The string
Type of person
and Date
Type of date
has a "have".
If there is one, TypeScript will be able to tell us if we have used the function incorrectly.
For example...
// @errors: 2345
function greet(person: string, date: Date) {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
greet("Maddison", Date());
Yes?
TypeScript reported an error with respect to the second argument, so why?
Perhaps surprisingly, in JavaScript Date()
When you call string
Returns the .
While new Date()
Using Date
You must create a type so that you can get back the results you originally expected.
Anyway, this error can be fixed very quickly.
function greet(person: string, date: Date) {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
greet("Maddison", new Date());
Keep in mind that you don't always have to write explicit type notation.
In many cases, TypeScript provides omitted type information. Can be deduced (or "find out").
let msg = "hello there!";
// ^?
msg
price string
Even if you haven't told TypeScript that you have a type, TypeScript can figure it out.
This is a basic feature, and if the type system takes care of it and can somehow figure out the correct type, it's best not to write down the type notation.
Note: The speech balloon in the code immediately above is what appears on the mouse hover screen when you write the code in the editor.
Erased Type
Functions written earlier greet
tsc
Let's see what happens when we compile it and get the JavaScript output.
// @showEmit
// @target: es5
function greet(person: string, date: Date) {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
greet("Maddison", new Date());
You can tell two things here:
person
anddate
Arguments no longer have type notation.- "Template String" - Backtick (
`
Sentences written using the character - is a concatenation operator (+
) converted to a regular string consisting of:
The second item will be discussed in more detail later, and the first item will be the first one.
Because type notation is not part of JavaScript (or strictly ECMAScript), there is currently no browser or runtime that can run TypeScript as-is without modification.
This is why when you want to use TypeScript, you need a compiler above all else. I need a way to remove or convert TypeScript-only code so that it can be executed.
Most TypeScript-only code is removed, and likewise, type notation is completely erased.
Remember: Type notation does not modify the runtime behavior of the program at all.
Downleveling
Another difference mentioned earlier, right below is the template string,
`Hello ${person}, today is ${date.toDateString()}!`;
It's been rewritten with the content below.
"Hello " + person + ", today is " + date.toDateString() + "!";
Why did this happen?
Template strings are ECMAScript 2015 (a.k.a. ECMAScript 6, ES2015, ES6, etc. Don't ask for more) is a feature that appeared in a version of ECMAScript.
TypeScript rewrites the code in a new version of ECMAScript into something older such as ECMAScript 3 or ECMAScript 5.
The process of replacing a new or "upper" version of ECMAScript with an old or "lower" version _Downleveling_It's also called .
The default behavior for TypeScript is to target a very older version of ECMAScript called ES3.
--target
You can also set flags to convert a more recent version to a target.
--target es2015
allows TypeScript to act as a target for ECMAScript 2015, which means that as long as ECMAScript 2015 is a supported runtime, the code will be converted to run.
consequently tsc --target es2015 input.ts
and you will get the output as shown below.
function greet(person, date) {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
greet("Maddison", new Date());
The default for the target version is ES3, but the vast majority of browsers in existence support ES2015.
So if maintaining compatibility with a particular older browser isn't a major issue, in most cases you can rest assured that ES2015 or higher can be targeted by the compiler.
Severity
The purpose of using TypeScript's type checker varies from user to user.
Someone may want to maintain a loose level of performing type checking on only a portion of the program, while still taking full advantage of its functionality as a useful programming tool.
This is the experience you want to provide as a base when using TypeScript. Type checking is optional, type inference is based on the most generous criteria, and the potential null
/undefined
No checks are made on the values.
These basic experiences are made in a way that does not interfere with the development experience. In the event of the aforementioned error tsc
is similar to how handles errors.
If you're migrating from traditional JavaScript, this is a good level to take the first step.
In contrast, the majority of users prefer TypeScript to perform type checking to the fullest extent. This is also why TypeScript provides a strictness setting.
This severity setting makes a static type checker as if it were close to a dial from a switch-level device (which simply weighs whether code checking has been done or not).
The farther you turn the dial, the more TypeScript will examine you.
That will give you a little more work to do, but in the long run, it's definitely worth it, and you'll be able to use more thorough inspections and precise tool features.
If possible, you should always enable strictness in new code.
TypeScript has several type-checking strictness flags that you can turn on and off, and all future example code will be written with all flags enabled unless otherwise noted.
From the CLI --strict
Set a flag or tsconfig.json
at "strict": true
Adding will activate all flags at the same time. You can also turn off each flag individually.
The two main options you should know are noImplicitAny
and strictNullChecks
Is.
noImplicitAny
In some cases, TypeScript does not deduce the type of the value, which is the most generous type. any
Please remember that it is considered to be.
This is not the worst case. Anyway, type any
is also a matter of course in normal JavaScript.
but any
Using often obscures the reason for using TypeScript in the first place.
The more specifically you use types in your program, the more validation and tooling features you can use, which means you'll encounter fewer bugs in your code.
noImplicitAny
When you enable the flag, the type is any
throws an error for variables that are implicitly deduced from .
strictNullChecks
null
and undefined
The default behavior is that values such as can be assigned to values of other types.
This makes it easy to code, but null
and undefined
Forgetting the treatment of is the cause of the countless bugs in the world. Some people may find this A Million Dollar MistakeIt's also called!
strictNullChecks
The flag is null
and undefined
to be more explicit, null
and undefined
Processing Forgot Whether or not you are having us in Liberate Gives.
Translation of TS for the New Programmer.md
title: TypeScript for the New Programmer
short: TS for the New Programmer
layout: docs
permalink: /ko/docs/handbook/typescript-from-scratch.html
oneline: Learn TypeScript from scratch
Congratulations on choosing TypeScript as your first language - a really good decision!
You've probably heard that Typescript is a "flavor" or "variant" of Javascript.
The relationship between TypeScript (TS) and JavaScript (JS) is quite unique in modern programming languages, so learning more about this relationship will help you learn how to add TypeScript to JavaScript.
A Short History of JavaScript (What is JavaScript? A Brief History)
JavaScript (also known as ECMAScript) was initially created as a scripting language for browsers.
JavaScript가 처음 나왔을 때, 수십 줄 이상의 코드를 작성하는 것은 다소 이례적인 일이었기에 웹 페이지� 속 짧은 코드들을 위해 사용할 것으로 여겨졌습니다.
Because of this, early web browsers took longer to execute more than a dozen lines of code.
However, as time went on and JS became more and more popular, web developers began to experience interactions using JS.
Web browser developers have optimized the execution engine (dynamic compilation) for the above increasing JS usage and extended what they can do with the optimized (adding APIs) to enable web developers to use more JS.
On modern websites, browsers frequently run applications that consist of hundreds of thousands of lines of code.
It starts with a simple network of static pages, and then goes all kinds of satisfying _Applications_It is a long and gradual growth of the "web" that has grown into a platform for .
In addition, JS has become famous enough to be used outside of the context of the browser, such as implementing JS servers using node.js.
The nature of JS, such as "works anywhere", makes it an attractive option for cross-platform development.
Today, many developers are only I'm programming the entire stack using only JavaScript!
In summary, we have JavaScript, the perfect tool designed for fast use and built to write millions of lines of applications.
Every language is its own Weird points - There are some weird and surprising things, and the proud but not proud beginnings of JavaScript are many You've created a problem. For example:
-
The same operator in JavaScript is (
==
a) argument By force conversion (coerces), causes unexpected behavior:if ("" == 0) { // 참입니다! 근데 왜죠?? } if (1 < x < 3) { // *어떤* x 값이던 참입니다! }
-
JavaScript also allows access to properties that do not exist:
const obj = { width: 10, height: 15 }; // 왜 이게 NaN이죠? 철자가 어렵네요! const area = obj.width * obj.heigth;
Most programming languages will display errors when this kind of error occurs, and some will display them during compilation, before the code is executed.
When you're writing a small program, these weird things get upsetting, but you can manage them. But when writing hundreds or thousands of lines of applications, these constant surprises are a serious problem.
TypeScript: A Static Type Checker
We've said earlier that some languages don't run buggy programs at all.
Detecting errors in code without letting the program run _Static Checks_is called.
어떤 것이 오류인지와 어떤 것이 연산 되는 값에 기인하지 않음을 정하는 것�이 정적 type Inspection.
_Static Type Tester_TypeScript is a type before running the program _Types of values_Looks for errors in the program based on .
For example, the reason for the error in the last example above is obj
of type Because.
The following error you may see in TypeScript:
// @errors: 2551
const obj = { width: 10, height: 15 };
const area = obj.width * obj.heigth;
A Typed Superset of JavaScript
So what does TypeScript have to do with JavaScript?
Syntax
TypeScript is allowed the syntax of JS, JavaScript Supersets The language.
Syntax refers to how you write code to create a program.
For example, the following code )
Because there is no syntax The error is:
// @errors: 1005
let a = (4
TypeScript doesn't see JavaScript code as an error because of its unique syntax.
That said, I don't know how it's written, but it works fine if I put the JavaScript code that works in a TypeScript file.
Types
However, TypeScript has added a way to use different kinds of values. Typed Superset.
gastric obj.heigth
The error is syntax The type of value, not the error (type) is the result of the wrong use of ).
As another example, when the following JavaScript code is executed in a browser, the following value is output: will:
console.log(4 / []);
The above code, which is syntactically-legal, is in JavaScript. NaN
Outputs the .
However, TypeScript determines that the operation of dividing a number into an array is not correct and throws an error:
// @errors: 2363
console.log(4 / []);
You can divide a number into an array with the intention of seeing what actually happens. But, most of them are programming mistakes.
TypeScript's Type Inspector is designed to help you create the right program while detecting as many common errors as possible.
(We'll look at the settings for how rigorously TypeScript can inspect your code later.)
If you move the code from the JavaScript file to the TypeScript code, depending on how you wrote the code, _Type Error_You can see it.
This could be a code problem, or TypeScript might be overly conservative.
To get rid of errors like the above, the guide will show you how to add various TypeScript syntax.
Runtime Behavior
TypeScript in JavaScript _Runtime characteristics_A programming language with
For example, in JavaScript, the act of dividing by 0 is not treated as a runtime exception and Infinity
Returns a value.
Logically, TypeScript is the runtime attribute of JavaScript code never It doesn't change.
This means that even if TypeScript detects that there is a type error in the code, moving the JavaScript code to TypeScript will execute in the same way. Guaranteed
Maintaining the same runtime behavior as JavaScript is a fundamental commitment of TypeScript to make it easy to switch between the two languages without worrying about nuances that can break your program's behavior.
Erased Types
Roughly, when TypeScript's compiler finishes checking the code, the type is By deleting The result is "compiled" code.
This means that once the code is compiled, the resulting regular JS code has no type information.
The absence of type information is due to the type inferred by TypeScript in the program. _characteristic_It means that it doesn't change.
In conclusion, type errors may be displayed during compilation, but the type system itself has nothing to do with how the program works when it is run.
Finally, TypeScript does not provide an additional runtime library.
TypeScript allows programs to use the same standard library (or external library) as a JavaScript program, so you don't have to study TypeScript-related frameworks further.
Learning JavaScript and TypeScript
It's often asked, "Should I learn JavaScript or TypeScript?" You can see questions like
The correct answer is that you can't learn TypeScript without learning JavaScript!
TypeScript shares syntax and runtime attributes with JavaScript, so everything you learn in JavaScript will help you learn TypeScript at the same time.
There are many JavaScript learning resources for programmers; TypeScript를 작성�할 때 그런 학습 자원을 무시해선 Not.
For example javascript
Tagged Questions typescript
About 20 times more than the tagged question, all javascript
The question can also be applied to TypeScript.
If you're looking for something like "How to sort a list in TypeScript", remember: typescript is the runtime of javascript that has a compile-time type tester.
The way you sort a list in TypeScript can be done the same way in JavaScript.
That's great if you've found a resource that uses TypeScript directly, but you don't have to limit everyday questions to TypeScript-specific answers to run runtime tasks.
Here, I recommend learning a few JavaScript basics (JavaScript Guide in Mozilla Web DocsThat would be fine.)
Once you've gotten used to it, come back and TypeScript for JavaScript ProgrammersRead on, handbookStart or ExampleTake a look.
Translation of TS for OOPers.md
title: TypeScript for Java/C# Programmers
short: TS for Java/C# Programmers
layout: docs
permalink: /ko/docs/handbook/typescript-in-5-minutes-oop.html
oneline: Learn TypeScript if you have a background in object-oriented languages
TypeScript is a popular choice for programmers familiar with languages that use static typing, such as C# and Java.
TypeScript's type system offers many benefits of static typing, such as better code completion, early detection of errors, and clearer communication between parts of a program.
TypeScript offers a lot of these developer-friendly features, but we need to revisit how JavaScript (and TypeScript, too) differs from traditional object-oriented programming (OOP) languages.
Understanding these differences will help you write better JavaScript code and avoid the common pitfalls of programmers who are just getting started with TypeScript in C#/Java.
Learning JavaScript Together (Co-learning JavaScript)
If you're already familiar with JavaScript but are primarily a programmer using Java or C#, this introductory page can help explain common misconceptions and pitfalls.
Some of the ways the TypeScript model types are quite different from Java or C#, and it's important to keep this in mind when learning TypeScript.
If you are a Java or C# programmer new to JavaScript, you should first use types to understand the runtime behavior of JavaScript. Except It's a good idea to learn some of the parts of JavaScript.
TypeScript code Run Because it doesn't change the way you do it, you still have to learn how JavaScript works in order to write code that actually makes something work!
TypeScript is the same as JavaScript _Runtime_Because of the use of , it is very important to remember that resources that you want to implement certain runtime actions (converting strings to numbers, displaying warnings, writing files to disk, etc.) always apply equally well to your TypeScript program.
Don't limit yourself to only resources specific to TypeScript!
Rethinking the Class
C# and Java are Compulsory OOP It's called a language.
In these languages _class_is not only the basic unit of code configuration, but all data at runtime and It is the basic container for behavior.
Forcing all functions and data to be in a class can be a good domain model for some problems, but all domains will be represented in this way. _need_is not.
Free Functions and Data
In JavaScript, functions can be anywhere, and you are free to pass data without belonging to a predefined 'class' or 'struct'.
This flexibility is very powerful.
Regardless of the OOP layer, "free" (non-class-agnostic) functions that process data are preferred as a model for writing programs in JavaScript.
Static Classes
Additionally, certain structures, such as singletons and static classes in C# and Java, are not required in TypeScript.
OOP in TypeScript
This means that you can continue to use the class if you want!
Some problems are suitable for solving with the existing OOP layer, and TypeScript supports classes in JavaScript, making these models more effective.
TypeScript supports many common patterns, such as interfaces, inheritance, and static method implementations.
We'll cover classes later in this guide.
Rethinking Types
TypeScript _type_The understanding of is actually quite different from C# or Java.
Let's look at some of the differences.
Nominal Reified Type Systems
In C# and Java, a given value and object has exactly one type: null, primitive type, or defined class type.
To ask for the exact type at runtime point value.GetType()
or value.getClass()
You can call methods such as .
The definition of this type exists somewhere in the class with a specific name, and cannot be used interchangeably with each other, even if the two classes have similar shapes, unless there is an explicit inheritance or a commonly implemented interface.
This aspect is reified, nominal Describes the type system.
The types you use in your code exist at runtime, and types are associated through declarations, not structures.
Types as Sets
In C# or Java, the one-to-one correspondence between runtime types and their compile-time declarations is important.
In TypeScript, types share something in common _A set of values_It's better to think of:
Because a type is only a set, a particular value is at the same time numerous Can belong to a set.
Once you start thinking of types as sets, certain operations become very natural.
For example, in C#, 'string' and 'int' Both are possible Since the type does not exist, it is strange to pass this value as an argument.
The moment you realize in TypeScript that all types are simply sets, this becomes very natural.
How would you describe the values that can belong to the 'string' set or the 'number' set?
This value is simply the value of the sets of Union: ‘string | It belongs to number'.
TypeScript provides several ways to use types based on set theory, and it is more intuitive to think of types as sets.
Erased Structural Types
In TypeScript, an object is exactly a single type. No.
For example, when you create an object that satisfies an interface, you can use the object where that interface is expected, even if there is no declarative relationship between the two.
interface Pointlike {
x: number;
y: number;
}
interface Named {
name: string;
}
function printPoint(point: Pointlike) {
console.log("x = " + point.x + ", y = " + point.y);
}
function printName(x: Named) {
console.log("Hello, " + x.name);
}
const obj = {
x: 0,
y: 0,
name: "Origin",
};
printPoint(obj);
printName(obj);
TypeScript's type system is not nominal. _Structured_Is: obj
is a number x
and y
As you have properties, Pointlike
can be used as:
The relationship between types is determined by the properties they contain, not by whether they are declared as a particular relationship.
TypeScript's type system is also Not materialized: At runtime obj
price Pointlike
It doesn't tell you.
In fact Pointlike
The type is at run time In any form Does not exist.
Types as a set In terms of concepts, obj
Pointlike
A set of values or Named
You can consider yourself a member of a set of values.
Consequences of Structural Typing
Object-oriented programmers are often surprised by two aspects of structured typing.
Empty Types
First _Empty Type_seems to ignore the expectation:
class Empty {}
function fn(arg: Empty) {
// 무엇인가를 하나요?
}
// 오류는 없지만, '빈' 타입은 아니지 않나요?
fn({ k: 10 });
TypeScript is a given argument that is valid Empty
Make sure that it is fn
checks whether the call to is valid.
{ k: 10 }
and class Empty { }
Check the _structure of _ to validate it.
Empty
Since there are no properties in Empty
to do all Properties { k: 10 }
Belongs to:
Therefore, a valid call is:
Surprisingly, it is used very similarly to the final nominal object-oriented programming language.
Because the natural subtype relationship between the derived class and the base of the derived class is destroyed, the subclass is _delete_I can't.
The structural type system describes the subtype in terms of having the attributes of a compatible type, so it implicitly distinguishes the above relationship
Identical Types
Another frequent cause of surprise is due to the same type:
class Car {
drive() {
// hit the gas
}
}
class Golfer {
drive() {
// hit the ball far
}
}
// No error?
let w: Car = new Golfer();
Again, the reason why it is not an error is because of the class _rescue_is because they are the same.
This may be a reason for potential confusion, but it's not uncommon for classes that don't really matter to be the same.
We'll learn more about how classes relate to each other in a later class chapter.
Reflection
Object-oriented programmers are familiar with being able to handle any type of value, including generics.
// C#
static void PrintType<T>() {
Console.WriteLine(typeof(T).Name);
}
Because TypeScript's type system has been completely cleared, information such as instantiation of generic type arguments is not available at runtime.
JavaScript has typeof
and instanceof
There are limited primitive elements such as , but you should be aware that these operators still work because they exist in the output of the type-cleared code.
For example typeof (new Car())
The Car
I "Car"
and not "object"
Is.
So far it has been an overview, here handbookor read the Playground exampleExplore .
Translation of TS for JS Programmers.md
title: TypeScript for JavaScript Programmers
short: TypeScript for JS Programmers
layout: docs
permalink: /ko/docs/handbook/typescript-in-5-minutes.html
oneline: Learn how TypeScript extends JavaScript
The relationship between TypeScript and JavaScript in modern programming languages is somewhat unique.
TypeScript sits on top of JavaScript as a layer, providing the functionality of JavaScript while adding its own layer on top of it. This layer is the TypeScript type system.
JavaScript is already string
, number
, object
, undefined
It has the same primitive type, but it doesn't check in advance that it is assigned consistently to the entire codebase. TypeScript acts as this layer.
This means that JavaScript code that already exists and works well is TypeScript code at the same time, but TypeScript's Type Inspector can highlight the discrepancy between what you think and what JavaScript actually does.
This tutorial provides a 5-minute overview of the type system with a focus on understanding the type system language extensions that TypeScript adds.
Types by Inference
TypeScript knows the JavaScript language and will generate types in most cases.
For example, if you create a variable and assign it to a specific value at the same time, TypeScript will use that value as the type of that variable.
let helloWorld = "Hello World";
// ^?
By understanding how JavaScript works, TypeScript can build a type system that accepts JavaScript code and has types. It provides a type system that eliminates the need to use additional characters to specify the type in the code. This is why in the example above the TypeScript is helloWorld
price string
This is how you will find out.
You've probably been using VS Code with JavaScript and using the editor's autocomplete feature when you're working.
This is because an understanding of JavaScript, which is indispensable to TypeScript, has been used internally to improve JavaScript work.
Defining Types
JavaScript is a dynamic language that enables a variety of design patterns. Some design patterns may not be able to provide types automatically (because you're probably using dynamic programming), in which case TypeScript supports an extension of the JavaScript language that allows TypeScript to specify what a type should be.
Here's how to name: string
and id: number
An example of creating an object with an inference type that includes .
const user = {
name: "Hayes",
id: 0,
};
To explicitly indicate the form of this object interface
Declare it as.
interface User {
name: string;
id: number;
}
Now after the variable declaration : TypeName
Using the syntax of a new JavaScript object interface
You can declare that you are following the form of .
interface User {
name: string;
id: number;
}
// ---cut---
const user: User = {
name: "Hayes",
id: 0,
};
If you create an object that doesn't fit that interface, TypeScript warns.
// @errors: 2322
interface User {
name: string;
id: number;
}
const user: User = {
username: "Hayes",
id: 0,
};
Because JavaScript supports class- and object-oriented programming, TypeScript is the same. - Interfaces can also be declared as classes.
interface User {
name: string;
id: number;
}
class UserAccount {
name: string;
id: number;
constructor(name: string, id: number) {
this.name = name;
this.id = id;
}
}
const user: User = new UserAccount("Murphy", 1);
Interfaces are also used to specify parameters and return values in functions.
// @noErrors
interface User {
name: string;
id: number;
}
// ---cut---
function getAdminUser(): User {
//...
}
function deleteUser(user: User) {
// ...
}
There are already a small number of primitive types available in JavaScript: boolean
, bigint
, null
, number
, string
, symbol
, object
and undefined
is available in the interface. TypeScript expands the list by adding a few things. For example any
(allows anything), unknown
(Make sure the person using this type has declared what the type is), never
(This type cannot be generated) void
(undefined
or a function that returns or has no return value).
You'll see pretty quickly that there are two constructs for building types: Interfaces and Types - interface
and when you need a specific feature type
must be used.
Composing Types
Similar to how to combine objects to create larger, more complex objects, TypeScript has tools to do this with types.
The two most commonly used code in everyday code to create new types using different types are Union and Generic.
Union
A union is a way of declaring that a type can be one of several types. For example boolean
Type true
or false
It can be described as:
type MyBool = true | false;
Consultation: MyBool
If you hover over it, boolean
- It's a property of the structured type system, which we'll look at later.
One of the most popular uses of union types is when values are allowed as follows: string
or number
of literalThe set is to describe:
type WindowStates = "open" | "closed" | "minimized";
type LockStates = "locked" | "unlocked";
type OddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
Union provides a way to handle various types, for example array
or string
There may be a function that receives the .
function getLength(obj: string | string[]) {
return obj.length;
}
TypeScript understands how variables change over time in your code, and you can use these checks to pick out types.
Type | Predicate |
---|---|
string | typeof s === "string" |
number | typeof n === "number" |
boolean | typeof b === "boolean" |
undefined | typeof undefined === "undefined" |
function | typeof f === "function" |
array | Array.isArray(a) |
For example typeof obj === "string"
Using the string
and array
and TypeScript knows that the object is in a different code path.
function wrapInArray(obj: string | string[]) {
if (typeof obj === "string") {
return [obj];
// ^?
} else {
return obj;
}
}
Generics
You can learn more about the TypeScript generic system, but for a 1-minute high-level explanation, generics are a way to provide variables to types.
Arrays are a common example, and arrays without generics can contain anything. An array with generics can describe the values in an array.
type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;
You can declare your own type using generics:
// @errors: 2345
interface Backpack<Type> {
add: (obj: Type) => void;
get: () => Type;
}
// 이 줄은 TypeScript에 `backpack`이라는 상수가 있음을 알리는 지름길이며
// const backpack: Backpack<string>이 어디서 왔는지 걱정할 필요가 없습니다.
declare const backpack: Backpack<string>;
// 위에서 Backpack의 변수 부분으로 선언해서, object는 string입니다.
const object = backpack.get();
// backpack 변수가 string이므로, add 함수에 number를 전달할 수 없습니다.
backpack.add(23);
Structural Type System
One of the core principles of TypeScript is that type checking has a value _form_is to concentrate on.
This is sometimes called "duck typing" or "structured typing."
In a structured type system, if two objects have the same shape, they are considered the same.
interface Point {
x: number;
y: number;
}
function printPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
// "12, 26"를 출력합니다
const point = { x: 12, y: 26 };
printPoint(point);
point
The variable is Point
Although never declared as a type, TypeScript can be used in type checking point
with the form of Point
Compare the forms of .
Since both are of the same form, it passes.
Form matching requires only a subset of the fields of the object to be matched.
// @errors: 2345
interface Point {
x: number;
y: number;
}
function printPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
// ---cut---
const point3 = { x: 12, y: 26, z: 89 };
printPoint(point3); // prints "12, 26"
const rect = { x: 33, y: 3, width: 30, height: 80 };
printPoint(rect); // prints "33, 3"
const color = { hex: "#187ABF" };
printPoint(color);
Finally, to wrap it up correctly, structurally there is no difference in how a class and an object follow a form:
// @errors: 2345
interface Point {
x: number;
y: number;
}
function printPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
// ---cut---
class VirtualPoint {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
const newVPoint = new VirtualPoint(13, 56);
printPoint(newVPoint); // prints "13, 56"
If all the necessary properties of an object or class exist, TypeScript will see them as consistent regardless of the implementation details.
Next Steps
This document is a high-level, 5-minute overview of the syntax and types of tools you use in your everyday code. From here:
- Complete Handbook From start to finish Read (30 minutes)
- Playground exampleExplore .
Translation of TS for Functional Programmers.md
title: TypeScript for Functional Programmers
short: TS for Functional Programmers
layout: docs
permalink: /ko/docs/handbook/typescript-in-5-minutes-func.html
oneline: Learn TypeScript if you have a background in functional programming
TypeScript is designed to bring traditional object-oriented programs to the web.
Microsoft programmers use traditional object-oriented types in JavaScript
It began as an attempt to import. As it has been developed, TypeScript's
The type system evolved into model code written by native JavaScript scripters.
The resulting system is powerful, interesting, and messy.
This introduction is for Haskell or ML programmers who want to learn TypeScript
Created for. The Haskell type system and the TypeScript type system
Explain the difference.
In addition, the TypeScript type system that occurs in the modeling of JavaScript code
Describes its unique features.
This introduction does not cover object-oriented programming.
In fact, TypeScript's object-oriented programs are available in other popular languages that have OO capabilities.
Similar to a program.
Prerequisites
This introduction assumes that you are aware of the following:
- Core concepts for programming in JavaScript.
- The type syntax of the C-family languages.
If you want to learn the core concepts of JavaScript
JavaScript: The Good PartsWould recommend.
A call-by-value lexic-scope language with a lot of variability
If you know how to write a program, you can still not read the book.
It doesn't matter.
R4RS Schemeis a good example.
C++ programming languageThe
It's great to learn about C-style type syntax.
Unlike C++, TypeScript uses postfix types, for example: string x
Instead of x: string
.
Concepts not in Haskell
Built-in types
In JavaScript, you define 8 built-in types:
type | explanation |
---|---|
Number |
Double-precision IEEE 754 floating-point. |
String |
Unmodifiable UTF-16 strings. |
BigInt |
An integer of any precision type. |
Boolean |
true and false . |
Symbol |
A unique value that you usually use as a key. |
Null |
Equivalent to unit type. |
Undefined |
Also equivalent to the unit type. |
Object |
Something similar to a record. |
For more information, see the MDN page..
TypeScript has native types that correspond to the built-in types:
number
string
bigint
boolean
symbol
null
undefined
object
Other important TypeScript types
type | explanation |
---|---|
unknown |
Top-level type. |
never |
Subtype. |
Object literals | yes { property: Type } |
void |
Intended to be used as a return type undefined A subtype of . |
T[] |
modifiable arrays, and also Array<T> Available as |
[T, T] |
Fixed length but modifiable tuple |
(t: T) => U |
function |
Please note:
-
The function syntax contains the parameter name. It's pretty hard to get used to!
let fst: (a: any, d: any) => any = (a, d) => a; // 또는 좀 더 정확하게 말하자면: let snd: <T, U>(a: T, d: U) => U = (a, d) => d;
-
The object literal type syntax is quite similar to the object literal value syntax:
let o: { n: number; xs: object[] } = { n: 1, xs: [] };
-
[T, T]
TheT[]
is a subtype of . Unlike Haskell, tuples are not related to lists.
Boxed types
JavaScript is a method that allows programmers to access that type.
I've been boxing the primitive types it contains equally. For example, in primitive form
number
and box form type Number
What's different about TypeScript
I've been reflecting.
The box shape type is very rarely needed when the method returns a primitive type.
(1).toExponential();
// 동등하게
Number.prototype.toExponential.call(1);
To call a method from a numeric literal, parenthesis the method to support the parser
Note that it must be put inside.
Gradual typing
Whenever TypeScript does not know the type of the expression, any
Type
use. Dynamic
Compared with ,any
is called a type in
It can also be called excessive.
It does not check the type every time it appears. For example any[]
It doesn't matter if you put any value in without checking it:
// tsconfig.json 파일에 "noImplicitAny": false 를 삽입, anys: any[]
const anys = [];
anys.push(1);
anys.push("oh no");
anys.push({ anything: "goes" });
and any
Types can be used anywhere:
anys.map(anys[1]); // 오 안되죠, "oh no" 함수가 아닙니다.
any
It can be contagious, too. — What if any
If you initialize a variable with an expression of type,
The variable is also any
Has a type.
let sepsis = anys[0] + anys[1]; // 어떤 의미로도 가능합니다.
TypeScript any
To raise an error when providing :
tsconfig.json
In "noImplicitAny": true
or "strict": true
must be set.
Structural typing
Although Haskell and most MLs don't type structurally,
Structured typing is a familiar concept for most functional programmers.
The basic form is quite simple:
// @strict: false
let o = { x: "hi", extra: 1 }; // 성공
let o2: { x: string } = o; // 성공
Here, the object literal { x: "hi", extra : 1 }
Matched to
{ x : string, extra : number }
There is. Two
A type has all the required properties and has a type that can be assigned to that property.
{ x : string }
can be assigned to:
The remaining properties do not prevent allocation, {x : string}
As a subtype of
Create.
Named types are just named in the type. For assignment, type aliases
One
and interface type Two
There is not much difference between them.
both p: string
I have properties.
(However, type aliases differ in interfaces related to recursive definitions and type parameters.
It works.)
// @errors: 2322
type One = { p: string };
interface Two {
p: string;
}
class Three {
p = "Hello";
}
let x: One = { p: "hi" };
let two: Two = x;
two = new Three();
Union
In TypeScript, union types are not tagged. To put it another way,
From Haskell data
Unlike , unions do not make a distinction.
However, you can distinguish types by different properties or unions that use built-in tags.
function start(
arg: string | string[] | (() => string) | { s: string }
): string {
// JavaScript에서 아주 일반적입니다
if (typeof arg === "string") {
return commonCase(arg);
} else if (Array.isArray(arg)) {
return arg.map(commonCase).join(",");
} else if (typeof arg === "function") {
return commonCase(arg());
} else {
return commonCase(arg.s);
}
function commonCase(s: string): string {
// 마지막으로, 다른 문자열로 변환합니다
return s;
}
}
string
, Array
and Function
is a type predicate
Built-in, else
Object types for branches are for convenience
It's a good idea to leave it at that.
However, it can generate unions that are difficult to distinguish at run time.
For new code, it's best to build only the distinct unions.
The following types have predicates:
type | predicate |
---|---|
string | typeof s === "string" |
number | typeof n === "number" |
bigint | typeof m === "bigint" |
boolean | typeof b === "boolean" |
symbol | typeof g === "symbol" |
undefined | typeof undefined === "undefined" |
function | typeof f === "function" |
array | Array.isArray(a) |
object | typeof o === "object" |
Functions and arrays are objects at runtime, but know that they have their own predicates
Let's take note.
intersection
In addition to Union, TypeScript also has intersections:
type Combined = { a: number } & { b: string };
type Conflicting = { a: number } & { a: string };
Combined
is as if it were written in a single object literal type.
a
and b
It has two properties: Interchange and union are recursive
By causing a crash in the case Conflicting.a: number & string
Is.
Unit types
A unit type is a subtype of a primitive type that contains exactly one raw value.
For example, a string "foo"
The Type "foo"
have.
JavaScript has no built-in enums, so it has a well-known set of strings.
It's common to use it instead.
String literal type unions follow this pattern in TypeScript:
declare function pad(s: string, n: number, direction: "left" | "right"): string;
pad("hi", 10, "left");
Extensible with the compiler if needed_ — As a parent type
convert — From primitive type to unit type, string
In "foo"
to
It happens when it is modifiable, and when you use some modifiable variables properly,
It may not work:
// @errors: 2345
declare function pad(s: string, n: number, direction: "left" | "right"): string;
// ---cut---
let s = "right";
pad("hi", 10, s); // 오류: 'string'은 '"left" | "right"'에 할당할 수 없습니다.
You may see an error like this:
- "right": "right"
- s: string
silver "right"
When is assigned to a modifiable variable. string
Can be extended to .
- string
silver "left" | "right"
Could not be assigned to .
s
can be solved using type notation in , but
As a result: "left" | "right"
A non-type variable
s
This will prevent it from being assigned to .
declare function pad(s: string, n: number, direction: "left" | "right"): string;
// ---cut---
let s: "left" | "right" = "right";
pad("hi", 10, s);
Concepts similar to Haskell
Contextual typing
TypeScript can deduce types, such as declaring variables.
There are a few obvious ways:
let s = "I'm a string!";
But if you've ever worked in another C-like language, you might not have expected it.
Type inference is possible in different ways:
declare function map<T, U>(f: (t: T) => U, ts: T[]): U[];
let sns = map((n) => n.toString(), [1, 2, 3]);
Here, in this example, n: number
In addition, T
and U
Before the call
Despite not being deduced.
indeed [1,2,3]
to T=number
After deducing the ,
n => n.toString()
As the return type of U=string
By inferring that,
sns
price string[]
Make sure you have a type.
Inference works in any order, but intellisense is only from left to right
Since it works, TypeScript works with arrays map
to declare the
Preferred:
declare function map<T, U>(ts: T[], f: (t: T) => U): U[];
Contextual typing also works recursively through object literals, otherwise
string
or number
It works as a deducible unit type with .
And you can deduce the return type through the context:
declare function run<T>(thunk: (t: T) => void): T;
let i: { inference: string } = run((o) => {
o.inference = "INSERT STATE HERE";
});
o
The type of { inference: string }
has been decided. because
- The declaration initializer is a declaration type:
{ inference: string }
Accordingly
The type is contextually defined. - Since the return type of the call uses a contextual type for reasoning,
The compiler isT={ inference: string }
to deduce. - Because the arrow function uses contextual types to specify a type for a parameter,
The compiler iso: { inference: string }
to provide.
While typing, o.
After typing the ,
Properties along with other properties in the actual program inference
to
It can be supplemented.
This feature is like an integrated type inference engine through TypeScript's reasoning
As it may seem, it is not.
Type aliases
The type alias is Haskell type
is a simple alias, as is the case with .
The compiler tries to use the alias name used in the source code
I try, but it doesn't always succeed.
type Size = [number, number];
let x: Size = [101.1, 999.9];
newtype
The most similar to tagged intersection Is:
type FString = string & { __compileTimeOnly: any };
FString
The compiler doesn't actually exist __compileTimeOnly
Called
It's like a regular string, except that I think I have properties.
FString
is still string
Can be assigned to, but
The opposite means impossible.
Discriminated unions
data
The most similar to , which is usually called a discriminant union in TypeScript,
A union of type with discriminant properties:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; x: number }
| { kind: "triangle"; x: number; y: number };
Unlike Haskell, tags or determinations are each just an attribute in an object type.
Unusual cases have the same properties as other unit types.
It's still a normal union type; Led |
The
It is an optional part of the union type syntax. Plain JavaScript using Union
It is distinguishable by code:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; x: number }
| { kind: "triangle"; x: number; y: number };
function area(s: Shape) {
if (s.kind === "circle") {
return Math.PI * s.radius * s.radius;
} else if (s.kind === "square") {
return s.x * s.x;
} else {
return (s.x * s.y) / 2;
}
}
area
The return type of is number
, which indicates that TypeScript is a function that is full
It's important to be aware of that. If some unusual cases are not covered,
area
The return type of is number | undefined
will be replaced by .
Also, unlike Haskell, common attributes appear in any union,
So it is useful to distinguish between multiple unions:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; x: number }
| { kind: "triangle"; x: number; y: number };
// ---cut---
function height(s: Shape) {
if (s.kind === "circle") {
return 2 * s.radius;
} else {
// s.kind: "square" | "triangle"
return s.x;
}
}
Type Parameters
Like most C-family languages, TypeScript allows the declaration of type parameters to be
Requires:
function liftArray<T>(t: T): Array<T> {
return [t];
}
There is no requirement for case, but type parameters are usually single uppercase.
Type parameters behave similarly to type class constraints.
Can be limited to types.
function firstish<T extends { length: number }>(t1: T, t2: T): T {
return t1.length > t2.length ? t1 : t2;
}
Because TypeScript can generally deduce type arguments from calls based on argument types.
It usually doesn't require type arguments.
Because TypeScript is structural, a name-based system requires as many type parameters as it does
Don't. In particular, make the function polymorphic
It doesn't have to be. Type parameters make the parameters the same type as
Like limiting type information Only to propagate
It should read:
function length<T extends ArrayLike<unknown>>(t: T): number {}
function length(t: ArrayLike<unknown>): number {}
First length
In T is not required; Referenced only once,
that it is not used to restrict the type of other parameters or return values.
Be aware.
Higher-kinded types
TypeScript has no type of supertype. Therefore, we do not allow you to:
function length<T extends ArrayLike<unknown>, U>(m: T<U>) {}
Point-free programming
Point-free programming is — Excessive use of curring and function synthesis
— This is possible in JavaScript, but can be verbose.
Since type inference for point-free programming in TypeScript often fails,
You will specify a type parameter instead of a value parameter.
The result is so verbose that you usually avoid point-free programming.
It's good.
Module system
import
or export
Except that the file containing is implicitly a module.
The modern module syntax in JavaScript is slightly similar to Haskell:
import { value, Type } from "npm-package";
import { other, Types } from "./local-package";
import * as prefix from "../lib/third-package";
you can import it into the commonjs module — node.js' module system
Modules used:
import f = require("single-function-package");
Export to the list:
export { f };
function f() {
return g();
}
function g() {} // g is not exported
Or by marking them individually:
export function f { return g() }
function g() { }
The latter style is more common, but both are also within the same file.
Allowed.
readonly
and const
(readonly
and const
)
In JavaScript, modifiability is the default,
_reference_to declare that it is inmodifiable const
You can declare a variable with .
The reference target is still modifiable:
const a = [1, 2, 3];
a.push(102); // ):
a[0] = 101; // D:
TypeScript is additionally attached to the properties readonly
You can use the controller.
interface Rx {
readonly x: number;
}
let rx: Rx = { x: 1 };
rx.x = 12; // error
Mapped Type Readonly<T>
All the properties readonly
to
Create a following:
interface X {
x: number;
}
let rx: Readonly<X> = { x: 1 };
rx.x = 12; // error
And to remove the method that is causing the side effect and prevent changes to the array index.
specific ReadonlyArray<T>
Type
There is a special syntax for this type:
let a: ReadonlyArray<number> = [1, 2, 3];
let b: readonly number[] = [1, 2, 3];
a.push(102); // error
b[0] = 101; // error
Only const-assertions that operate on arrays and object literals
You can use:
let a = [1, 2, 3] as const;
a.push(102); // error
a[0] = 101; // error
However, these features are not basic functions, so the TypeScript code
You don't have to use it consistently.
Next Steps
This document contains an overview of the high level of syntax and types in everyday code. From here, you can refer to the following:
- Complete Handbook From start to finish Read (30m)
- Playground exampleTake a look.
Translation of By Example.md
title: Declaration Reference
layout: docs
permalink: /ko/docs/handbook/declaration-files/by-example.html
oneline: "How to create a d.ts file for a module"
Introduction
This guide is written to explain how to write a quality declaration file.
This guide shows some of the API documentation along with examples of using the API.
Describes how to write the corresponding declaration.
The examples usually get more complex towards the second half.
- Objects with Properties
- Overloaded Function
- Reusable Types (Interfaces)
- Reusable Types (Type Aliases)
- Organizing Types
- Classes
- Global Variables
- Global Functions
The Examples
Objects with Properties
document
Global Variables
myLib
There is a function to create a greetingmakeGreeting
and
Indicates the number of greetings you have created so farnumberOfGreetings
There are properties.
code
let result = myLib.makeGreeting("hello, world");
console.log("The computed greeting is:" + result);
let count = myLib.numberOfGreetings;
declaration
To describe a type or value approaching in dot notation declare namespace
Use .
declare namespace myLib {
function makeGreeting(s: string): string;
let numberOfGreetings: number;
}
Overloaded Functions
document
getWidget
The function returns a Widget by taking a number as an argument, or a string as an argument and returning a Widget array.
code
let x: Widget = getWidget(43);
let arr: Widget[] = getWidget("all of them");
declaration
declare function getWidget(n: number): Widget;
declare function getWidget(s: string): Widget[];
Reusable Types (Interfaces)
document
When specifying a greeting, be sure to
GreetingSettings
You must pass an object.
This object has the following properties:1 - greeting: required string
2 - duration: Optional Time (milliseconds)
3 - color: optional string, e.g. '#ff00ff'
code
greet({
greeting: "hello world",
duration: 4000
});
declaration
To define a type with properties interface
Use .
interface GreetingSettings {
greeting: string;
duration?: number;
color?: string;
}
declare function greet(setting: GreetingSettings): void;
Reusable Types (Type Aliases)
document
Wherever a greeting is expected,
string
,string
A function that returns a , orGreeter
You can pass the instance.
code
function getGreeting() {
return "howdy";
}
class MyGreeter extends Greeter { }
greet("hello");
greet(getGreeting);
greet(new MyGreeter());
declaration
You can use a type alias as an abbreviation for a type:
type GreetingLike = string | (() => string) | Greeter;
declare function greet(g: GreetingLike): void;
Organizing Types
document
greeter
The object can write logs to a file or display a warning window.
Log Options.log(...)
Inside, the warning window option.alert(...)
It can be passed inside.
code
const g = new Greeter("Hello");
g.log({ verbose: true });
g.alert({ modal: false, title: "Current Greeting" });
declaration
Use namespaces to structure types.
declare namespace GreetingLib {
interface LogOptions {
verbose?: boolean;
}
interface AlertOptions {
modal: boolean;
title?: string;
color?: string;
}
}
You can make nested namespaces into a single declaration:
declare namespace GreetingLib.Options {
// Refer to via GreetingLib.Options.Log
interface Log {
verbose?: boolean;
}
interface Alert {
modal: boolean;
title?: string;
color?: string;
}
}
Classes
document
Greeter
You can instantiate an object to create a greeter, or you can inherit from it to create a custom greeter.
code
const myGreeter = new Greeter("hello, world");
myGreeter.greeting = "howdy";
myGreeter.showGreeting();
class SpecialGreeter extends Greeter {
constructor() {
super("Very special greetings");
}
}
declaration
To describe a class or a class-like object declare class
Use .
A class can have properties and methods as well as constructors.
declare class Greeter {
constructor(greeting: string);
greeting: string;
showGreeting(): void;
}
Global Variables
document
Global Variables
foo
contains the number of widgets that exist.
code
console.log("Half the number of widgets is " + (foo / 2));
declaration
To declare a variable declare var
Use .
If the variable is read-only, declare const
Use .
If the variable is a block-scope declare let
You can also use it.
/** 존재하는 위젯의 수 */
declare var foo: number;
Global Functions
document
To show the user a greeting
greet
You can call the function.
code
greet("hello, world");
declaration
To declare a function declare function
Use .
declare function greet(greeting: string): void;
@microsoft-github-policy-service agree |
1 similar comment
@microsoft-github-policy-service agree |
Thank you for PR!! 🙇 But, the #167 issue is not only If you use the word |
@KunHwanAhn I used |
LGTM |
Merging because @dvlprsh is a code-owner of all the changes - thanks! |
Fix #167