fuafa / not-a-hub Goto Github PK
View Code? Open in Web Editor NEWblog, IP has been blocked by ***, effort needed to visit
Home Page: https://www.fahub.info
blog, IP has been blocked by ***, effort needed to visit
Home Page: https://www.fahub.info
// 在一个函数调用 F(args) 中,如果一个参数表达式 args 是一个范型函数 H,那么 H 中得类型参数 T 会传播到返回类型中,当且仅当:
// | | | |
// pipe(list, box) (list or box) (list<T>, box<V>) (T, V)
// 1. 当 F 是一个范型函数而且返回一个函数 G 只有一个 single call signature (怎么翻译。。。)
// | |
// pipe<A extends any[], B, C> (...args: A) => C
// 2. G 本身并不会引入新的类型参数
// |
// (...args: A) => C 中 A, C 都来自 pipe
// 3. in the left-to-right processing of the function call arguments,
// no inferences have been made for any of the type parameters referenced in the contextual type for the argument expression.(啥意思?)
// 尝试解读:比如 pipe(list, box) 对于 list<T> 中的 T 没有发生任何的推导,只有 propagation.
declare function pipe<A extends any[], B, C>(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C;
declare function list<T>(a: T): T[];
declare function box<V>(x: V): { value: V };
const listBox = pipe(list, box); // <T>(a: T) => { value: T[] }
const boxList = pipe(box, list); // <V>(x: V) => { value: V }[]
// 不能从右到左推导
const arrowBox = pipe(x => [x], box) // (x: any) => { value: any[] }
const x1 = listBox(42); // { value: number[] }
const x2 = boxList("hello"); // { value: string }[]
type EventHandler<T> = { bivarianceHack(data: T): void }['bivarianceHack']
interface FormProp<T> {
onChange: EventHandler<T>
onChange2: <R extends string>(data: R) => void
onChange3<S extends string>(data: S): void
onChange4(data: string): void
onChange5: (data: string) => void
}
declare const Form: React.ComponentType<FormProp<string>>
declare const onChange: (data: '') => void
<Form
onChange={onChange} // pass
onChange2={onChange} // fail
onChange3={onChange} // fail
onChange4={onChange} // pass
onChange5={onChange} //fail
/>
I think firefox silently fails since I mutated the imported object
在 TypeScript 中, 已知 A <: B
, B :< C
, 并不能推断出 A <: C
, 例如
number <: any
, any <: string
;{x: number, y: string} <: {x: number}
, {x: number} <: {x: number, y?: string}
;number <: Object
, Object <: object
extends
), 称之为 Non-distributive Conditional Types.type NonDistributive<T> = string extends T ? true : false;
extends
), 称之为 Distributive Conditional Types.type Distributive<T> = T extends string ? true : false;
type Resolved = Distributive<string> // resolved to true;
type Deferred<T extends string> = NonDistributive<T> // deferred.
definitely true
, or definitely false
.type StillDeferred<T extends string> = Distributive<T>; // deferred.
如果 T in StillDeferred <: string
, 难道推不出来 T in Distributive <: string
吗?
Why: Conditional type resolution 会忽略 type parameter constraints.
Why Why: /master/src/compiler/checker.ts
-> createTypeChecker
-> getConditionalType
, 大概 10705 行
// Return trueType for a definitely true extends check. We check instantiations of the two
// types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
// that has no constraint. This ensures that, for example, the type
// type Foo<T extends { x: any }> = T extends { x: string } ? string : number
// doesn't immediately resolve to 'string' instead of being deferred.
在 PostList 页面 -> 前往下一页 -> 点击一篇文章或者点击一个 tag -> 返回 -> 变成了第一页
Int
, Add
, Negate
.evalExp
, toString
, hasZero
on each data variance./**
* THE GRID
* evalExp toString hasZero noNegConstants (to be extended)
*
* Int
*
* Add
*
* Negate
*
* Multiply (to be extended)
*
*/
noNegConstants
, we just need to add a new function and keep the remaining unchanged.Multiply
, we would need to alter 4 blocks of code.// 写成这样是想要有 pattern matching 的支持,
// 然而只能做到 exhaustive check, 而没有解构.
type Exp =
{ kind: 'Int', value: Int }
| { kind: 'Negate', value: Negate}
| { kind: 'Add', value: Add }
// hard
// | { kind: 'Multiply', value: Multiply}
// ts 没有 type constructor, 所以需要另外给每一个 variance 新建一个 class.
// 在支持 type constructor 的语言中, 例如 ml 系, 可以写成:
// datatype Exp = Int of int | Negate of Exp | Add of Exp * Exp
class Int {
v: number;
constructor(v: number) {
this.v = v;
}
}
class Negate {
v: Exp;
constructor(v: Exp) {
this.v = v;
}
}
class Add {
v1: Exp;
v2: Exp;
constructor(v1: Exp, v2: Exp) {
this.v1 = v1;
this.v2 = v2;
}
}
// hard
// class Multiply {
// e1: Exp;
// e2: Exp;
// constructor(e1: Exp, e2: Exp) {
// this.e1 = e1;
// this.e2 = e2;
// }
function addValue(v1: Exp, v2: Exp): Exp {
if (v1.kind !== 'Int' || v2.kind !== 'Int') {
throw new Error('Non-numbers in addition')
}
return {
kind: 'Int',
value: new Int(v1.value.v + v2.value.v)
}
}
function evalExp(e: Exp): Exp {
switch(e.kind) {
case 'Int':
return e;
case 'Negate':
const e1 = evalExp(e.value.e);
if (e1.kind === 'Int') {
return {
kind: 'Int',
value: new Int(-e1.value.v)
};
}
throw new Error('Non-numbers in negation');
case 'Add':
return addValue(
evalExp(e.value.e1),
evalExp(e.value.e2)
);
// hard
// case 'Multiply':
// ...
}
}
function toString(e: Exp): string {
switch(e.kind) {
case 'Int':
return String(e.value.v);
case 'Negate':
return `-${toString(e.value.e)}`;
case 'Add':
return `${toString(e.value.e1)} + ${toString(e.value.e2)}`;
// hard
// case 'Multiply':
// ...
}
}
function hasZero(e: Exp): boolean {
switch(e.kind) {
case 'Int':
return e.value.v === 0;
case 'Negate':
return hasZero(e.value.e);
case 'Add':
return hasZero(e.value.e1) || hasZero(e.value.e2);
// hard
// case 'Multiply':
// ...
}
}
// easy
// function noNegConstants(e: Exp): Exp {
// switch(e.kind) {
// case 'Int':
// case 'Negate':
// case 'Add':
// // case 'Multiply'
// }
// }
Multiply
.noNegConstants
.interface Exp {
evalExp(): Int;
toString(): string;
hasZero(): boolean;
}
class Int implements Exp {
v: number;
constructor(v: number) {
this.v = v;
}
evalExp() {
return this;
}
toString() {
return String(this.v);
}
hasZero() {
return this.v === 0;
}
}
class Negate implements Exp {
e: Exp
constructor(e: Exp) {
this.e = e;
}
evalExp() {
return new Int(this.e.evalExp().v);
}
toString() {
return `-${this.e.toString()}`;
}
hasZero() {
return this.e.hasZero();
}
}
class Add implements Exp {
e1: Exp;
e2: Exp;
constructor(e1: Exp, e2: Exp) {
this.e1 = e1;
this.e2 = e2;
}
evalExp() {
return new Int(this.e1.evalExp().v + this.e2.evalExp().v);
}
toString() {
return this.e1.toString() + this.e2.toString();
}
hasZero() {
return this.e1.hasZero() || this.e2.hasZero();
}
}
Suppose there are two more variances to be extended MyString
and Rational
, and the function add_values
now work for any pairs of the variances but not just the Int
. If one of the candidate is of type MyString
, then we do the concatenation.
# Any functor must have a `map` method:
map :: Functor f => f a ~> (a -> b) -> f b
Since there is no Setoid
restriction on b
, b
may not be comparable, but Set
only contains value which is comparable
dagaishizheyang
currently client side code are all sitting inside /src
Use useLayoutEffect
instead of useEffect
Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().
facebook/react#14174
我的 PR 不可能被 APPROVED
issue
then quickly click pr
issue
feedsproject
|- src
|- index.js
|- package
|- module.js
|- module.d.ts
index.js
中 import
module// module.js
export function foo(x) {
return x;
}
// module.d.ts
export declare function foo(x: number): number;
// index.js
import { foo } from './src/module';
// foo 的类型是 number -> number
// 因为有一个同名的 d.ts 文件,TypeScript 可以找到相对应的类型,
// 但是生成 JS 文件中 `foo` 还是会正确的指向 module.js 中的 `foo`
foo
// module.js
// foo 的类型是 any -> any
export function foo(x) {
return x;
}
因为 module.js 和 module.d.ts 是两个不同的 module(指 ES 中的 module), 他们有属于自己的作用域。
目前只能通过在 js-doc 中使用动态 import
的语法,把 foo
联系起来。
// module.js
/**
*
* @type {import("./module").foo}
* 这里 foo 的类型是 number -> number
*/
export function foo(x) { return x; }
如果 module 里有多个方法,那么
/**
*
* @typedef {import("./module")} Module
*/
/**
*
* @type {Module["foo"]}
*/
export function foo(x) {
return {}
}
未来可能会引入新的 js-doc tag named @import
and @from
, 好处是看起比上面的 intuitive.
有两种 proposals:
/**
*
* @from "./module"
* @import { foo } from
* @import Default
* @import * as ns
*/
/**
* @import { foo, y as z, default as Default } from "./module"
*/
这么麻烦,还不如直接写 TypeScript...
microsoft/TypeScript#14342
microsoft/TypeScript#14377
microsoft/TypeScript#14844
microsoft/TypeScript#22160
type IsString<X> = [X] extends [string] ? true : false
function isString<X extends string, Y>(x: X, y: Y) {
if (typeof x === "string") {
// 因为 typeof x === 'string' 并没有为 X 增加额外的信息 (X 本来就 extends string)
x; // X extends string,
const a: IsString<typeof x> = true; // error: conditional type is deferred
}
if (typeof y === "string") {
// 1. Y 原来并没有任何约束, (no extends)
// 2. typeof y === 'string' -> typeof y <: string,
// 3. 同时 y: Y,
// 4. 所以 typeof y <: Y & string
y; // Y & string,
const b: IsString<typeof y> = true;
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.